Hibernate Search 中文操作指南

21. Known issues and limitations

21.1. Without coordination, in rare cases, indexing involving @IndexedEmbedded may lead to out-of sync indexes

21.1.1. Description

在默认设置( no coordination)中,如果两个实体实例在同一“索引-嵌入”实体中 indexed-embedded,并且这两个实体实例在并行事务中更新,那么存在一个小风险,即事务提交刚好错误,导致索引-嵌入实体仅部分重新进行索引更新。

例如,考虑一个索引实体 A,该索引嵌入了 B 和 C。以下涉及两个并行事务(T1 和 T2)的事件过程将导致索引过时:

  1. T1: Load B.

  2. T1: 以需要为 A 重新建立索引的方式更改 B。

  3. T2: Load C.

  4. T2: 以需要为 A 重新建立索引的方式更改 C。

  5. T2: 请求事务提交。Hibernate Search 为 A 构建文档。在此过程中,它会自动加载 B。B 显示未修改,因为 T1 尚未提交。

  6. T1: 请求事务提交。Hibernate Search 构建待索引文档。在此过程中,它会自动加载 C。C 显示未修改,因为 T2 尚未提交。

  7. T1: 已提交事务。Hibernate Search 会自动向索引发送更新后的 A。在此版本中,已更新 B,但未更新 C。

  8. T2: 已提交事务。Hibernate Search 会自动向索引发送更新后的 A。在此版本中,已更新 C,但未更新 B。

此事件链将结束于一个索引,其中包含已更新 C 但未更新 B 的 A 版本。

21.1.2. Solutions and workarounds

以下解决方案可以帮助规避此限制:

21.1.3. Roadmap

此限制是由线程或应用程序节点之间缺乏协调直接造成的,因此只能通过配置 coordination完全解决。

目前路线图中没有其他解决方案。

21.2. Without coordination, backend errors during indexing may lead to out-of sync indexes

21.2.1. Description

使用默认设置 ( no coordination ) 时, indexing 实际上会在事务提交后立即在后端应用索引更改,而不会对索引更改进行任何类型的交易记录。

因此,如果在索引期间后端发生错误(即 I/O 错误),则将取消此索引,而无法取消对应的数据库事务:因此索引将变得不同步。

21.2.2. Solutions and workarounds

以下解决方案可以帮助规避此限制:

21.2.3. Roadmap

此限制是由于缺少对实体更改事件的持久性直接导致的,因此仅能通过以下方式来彻底解决:持久化这些事件,例如切换到 outbox-polling coordination strategy

未来版本中可能会考虑一些不完整的对策,例如自动的线程内重试,但它们永远无法完全解决问题,而且它们目前不在路线图中。

21.3. Listener-triggered indexing only considers changes applied directly to entity instances in Hibernate ORM sessions

21.3.1. Description

由于 how Hibernate Search uses internal events of Hibernate ORM为了检测更改,它不会检测_insert_/delete/_update_查询(无论是 SQL 查询还是 JPQL/HQL 查询)导致的更改。

这是因为这些查询是在数据库端执行的,而 Hibernate ORM 或 Search 并不了解实际上创建、删除或更新了哪些实体。

21.3.2. Solutions and workarounds

一种解决方法是,使用 MassIndexerJakarta Batch mass indexing jobexplicitly ,在运行 JPQL/SQL 查询后显式重新索引。

21.3.3. Roadmap

实际检测这些更改的一种解决方案是直接从数据库中获取实体更改事件,例如使用 Debezium。

这在 HSEARCH-3513中作为跟踪,但仍然是长期的目标。

21.4. Listener-triggered indexing ignores asymmetric association updates

21.4.1. Description

Hibernate ORM 能够处理关联的不对称更新,其中只有关联的所有者端得到更新且另一端被忽略。会话中的实体将在会话持续期间不一致,但在重新加载后,它们将再次保持一致,这是由于实体加载的工作方式。

这种关联的不对称更新做法通常会在应用程序中引起问题,在 Hibernate Search 中也如此,它可能导致索引不同步。因此,必须避免。

例如,我们假设一个索引实体 A 与实体 @IndexedEmbedded 具有 A.b 关联 B,且 B 在其端拥有该关联,B.a。只需将 B.a 设置为 null 即可移除 AB 之间的关联,数据库的效果将与我们希望的一样。

但是,Hibernate Search 将只能检测到 B.a 发生了变化,并且当它尝试推理需要重新索引哪些实体时,它将不再能够知道 B.a 以前指的是什么。这种变化本身对 Hibernate Search 来说是无用的:Hibernate Search 将不知道需要重新索引 A。它会“忘记”重新索引 A,导致 A.b 仍包含 B 的不同步索引。

最终,Hibernate Search 了解需要重新索引 A 的唯一方法是同时将 A.b 设置为 null,这将导致 Hibernate Search 检测到 A.b 已更改,从而 A 也已更改。

21.4.2. Solutions and workarounds

以下解决方案可以帮助规避此限制:

21.4.3. Roadmap

将来,Hibernate Search 可能会处理非对称关联更新,方法是对从关联中添加/删除的实体进行跟踪。但只有在后台线程中异步进行索引时,此方法才能彻底解决该问题,例如使用 outbox-polling coordination strategy 。此方法已作为 HSEARCH-3567 进行跟踪。

或者,使用 Debezium 等工具直接从数据库中获取实体变更事件也能解决此问题。这在 HSEARCH-3513中作为跟踪,但仍然是长期的目标。

21.5. Listener-triggered indexing is not compatible with Session serialization

21.5.1. Description

listener-triggered indexing启用时,Hibernate Search 收集实体更改事件,以在 ORM EntityManager/_Session_内部构建“索引计划”。索引计划包含有关需要重新索引的实体的信息,有时也包含尚未索引的文档。

索引计划无法被序列化。

如果 ORM Session 被序列化,则在反序列化会话时所有收集的更改事件都将丢失,而 Hibernate Search 可能“忘记”重新为某些实体建立索引。

在大多数应用中都没问题,因为他们并不用依赖会话的序列化,但是对于依赖 Bean 钝化的某些 JEE 应用来说,这可能是个问题。

21.5.2. Solutions and workarounds

在更改实体后,避免序列化 ORM EntityManager/Session

21.5.3. Roadmap

没有计划来解决此限制。当 Hibernate Search 被启用时,我们不打算支持 Session 序列化。