Hibernate Search 中文操作指南

5. Architecture

5.1. Components of Hibernate Search

从用户的角度来看,Hibernate Search 由以下两个组件组成:

Mapper

映射器将用户模型“映射”到索引模型,并提供与用户模型一致的 API 来执行索引和搜索。

大多数应用程序依赖于 Hibernate ORM mapper,它提供索引 Hibernate ORM 实体属性的能力,但也存在一个可以在不使用 Hibernate ORM 时使用的 Standalone POJO mapper

部分通过领域模型上的注释,部分通过配置属性来配置映射器。

Backend

后端是全文引擎的抽象,其中“完成任务”。通过“索引管理器”实现通用索引和搜索接口,每个管理器提供对一个索引的访问。

例如, Lucene backend委托给 Lucene 库,而 Elasticsearch backend委托给远程 Elasticsearch 集群。

后端部分由映射程序配置,它会告诉后端哪些索引必须存在以及它们必须有什么字段,部分通过配置属性配置。

映射程序和后端协同工作,提供以下三个主要功能:

Mass indexing

这就是 Hibernate Search 如何根据数据库的内容从零重建索引。

映射程序查询数据库以检索每个实体的标识符,然后批量处理这些标识符,加载实体并对其进行处理,以生成要发送到后端进行索引的文档。后端将文档放入内部队列中,并将在后台进程中批量处理文档,并在完成后通知映射程序。

有关详细信息,请参阅 Indexing a large amount of data with the MassIndexer

Explicit and listener-triggered indexing

显式和侦听器触发的索引依赖于索引计划 ( SearchIndexingPlan ) 来基于有限更改索引特定实体。

使用 explicit indexing时,调用方会将实体更改的信息显式传给 indexing plan;使用 listener-triggered indexing时,实体更改在 the Hibernate ORM integration(带有 a few exceptions)中以透明方式检测到,并自动添加到索引计划中。

侦听器触发的索引仅在 the Hibernate ORM integration 的上下文中才有意义;有 no such feature available for the Standalone POJO Mapper 。在两种情况下, indexing plan 会从这些更改中推断出实体是否需要重新索引,可能是更改的实体本身或 other entities that embed the changed entity in their index

在事务提交时,将处理索引计划中的更改(在同一线程或后台进程中,具体取决于 coordination strategy),生成文档,然后将其发送到后端进行索引。后端将文档放入内部队列中,并在后台进程中分批索引文档,并在完成时通知映射器。

有关详细信息,请参见 Implicit, listener-triggered indexing

Searching

这就是 Hibernate Search 提供查询索引的方法。

映射程序公开对搜索 DSL 的入口点,允许选择要查询的实体类型。当选择一个或多个实体类型时,映射程序将委派给相应的索引管理器以提供搜索 DSL,并最终创建搜索查询。在查询执行时,后端会向映射程序提交实体引用的列表,然后映射程序加载相应的实体。然后由查询返回实体。

有关详细信息,请参见 Searching

5.2. Examples of architectures

5.2.1. Overview

表 2. 架构的比较

Architecture

Single-node with Lucene

No coordination with Elasticsearch

Outbox polling with Elasticsearch

Compatible mappers

Hibernate ORM integrationStandalone POJO Mapper

Hibernate ORM integration only

Application topology

Single-node

Single-node or multi-node

Extra bits to maintain

Indexes on filesystem

Elasticsearch cluster

Guarantee of index updates

Non-transactional, after the database transaction / SearchSession.close() returns

Transactional, on database transaction commit

Visibility of index updates

Configurable: immediate or eventual

Configurable: immediate (poor performance) or eventual

Eventual

Native features

Mostly for experts

For anyone

Overhead for application threads

Low to medium

Very low

Overhead for the database

Low

Low to medium

Impact on database schema

None

Extra tables

Limitations

监听器触发索引忽略: JPQL/SQL queriesasymmetric association updates

在极少数情况下索引不同步: concurrent @IndexedEmbeddedbackend I/O errors

No other known limitation

5.2.2. Single-node application with the Lucene backend

Description

使用 Lucene backend时,索引局部于给定的应用程序节点 (JVM)。通过直接调用 Lucene 库来访问它们,而无需通过网络。

architecture single node lucene

此模式仅与单节点应用程序相关。

Pros and cons

优点:

  1. 简单性:无需外部服务,所有内容都存在于同一服务器上。

  2. Immediate visibility(~毫秒)的索引更新。虽然其他体系结构对于大多数用例都能执行得很好,但如果您需要在数据库更改后立即可见更改,那么单节点 Lucene 后端是实现索引的最佳方式。

缺点:

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

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

  3. 不易扩展:经验丰富的开发者可以通过提供本机 Lucene 对象来访问许多 Lucene 特性,甚至包括 Hibernate Search 未公开的特性;然而,对于不熟悉 Lucene 的开发者来说,Lucene API 并不是非常容易理解。如果您感兴趣,请参阅 Query-based predicates

  4. 应用程序线程开销:重新索引直接在应用程序线程中完成,可能需要额外时间来加载必须从数据库索引的数据。根据需要加载的数据量,这可能会增加应用程序的延迟和/或降低其吞吐量。

  5. 无水平可扩展性:只能有一个应用程序节点,所有索引都需要驻留在同一服务器上。

Getting started

若要实现此架构,请使用以下 Maven 依赖项:

<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-mapper-orm</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>
<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-backend-lucene</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>

With the Standalone POJO Mapper (no Hibernate ORM)

<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-mapper-pojo-standalone</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>
<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-backend-lucene</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>

5.2.3. Single-node or multi-node application, without coordination and with the Elasticsearch backend

Description

使用 Elasticsearch backend时,索引不绑定到应用程序节点。它们由一个单独的 Elasticsearch 节点集群管理,并通过对 REST API 的调用来访问。

因此,可以按以下方式设置多个应用程序节点,使它们全部独立执行索引更新和搜索查询,而无需相互协调。

architecture no coordination elasticsearch
Pros and cons

优点:

  1. 易于扩展:您可以通过提供 JSON 来轻松访问大多数 Elasticsearch 功能,即使 Hibernate Search 中没有提供这些功能。例如,请参阅 JSON-defined predicatesJSON-defined aggregationsleveraging advanced features with JSON manipulation

  2. 索引的水平可扩展性:您可以根据需要调整 Elasticsearch 集群的大小。请参阅 "Scalability and resilience" in the Elasticsearch documentation

  3. 应用程序的水平可扩展性:您可以拥有任意数量的应用程序实例(虽然高并发性增加了此体系结构中出现某些问题的可能性,请参阅下文的“缺点”)。

缺点:

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

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

  3. 需要管理一个附加服务:Elasticsearch 集群。

  4. 应用程序线程开销:重新索引直接在应用程序线程中完成,可能需要额外时间来加载必须从数据库索引的数据。根据需要加载的数据量,这可能会增加应用程序的延迟和/或降低其吞吐量。

  5. ~1 秒的索引更新(近乎实时)。虽然在数据库更改后,立即就可以看到更改,但 Elasticsearch 属于 near-real-time,如果您需要在数据库更改后立即看到更改,那么它的性能不会很好。

Getting started

若要实现此架构,请使用以下 Maven 依赖项:

<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-mapper-orm</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>
<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-backend-elasticsearch</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>

With the Standalone POJO Mapper (no Hibernate ORM)

<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-mapper-pojo-standalone</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>
<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-backend-elasticsearch</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>

5.2.4. Multi-node application with outbox polling and Elasticsearch backend

以下列出的特性尚处于 incubating 阶段:它们仍在积极开发中。

通常 compatibility policy 不适用:孵化元素(例如类型、方法、配置属性等)的契约在后续版本中可能会以向后不兼容的方式更改,甚至可能被移除。

我们建议您使用孵化特性,以便开发团队可以收集反馈并对其进行改进,但在需要时您应做好更新依赖于这些特性的代码的准备。

Description

使用 Hibernate Search 的 outbox-polling coordination strategy ,实体更改事件不会在出现它们的 ORM 会话中立即处理,而是推送到数据库中的出站表中。

一个后台进程轮询出站表以查找新事件,并异步处理它们,根据需要更新索引。由于该队列 can be sharded,多个应用程序节点可以共享索引工作负载。

这需要 Elasticsearch backend,以便索引不绑定到单个应用程序节点,并且可以从多个应用程序节点更新或查询。

architecture outbox polling elasticsearch
Pros and cons

优点:

  1. Safest:

在这里消除了其他体系结构中导致不同步索引的事件,因为实体更改事件 are persisted in the same transaction as the entity changes允许无限次重试。

在这里消除了其他体系结构中导致不同步索引的事件,因为在重新索引之前 each entity instance is reloaded from the database within a new transaction

  1. 在这里消除了其他体系结构中导致不同步索引的事件,因为实体更改事件 are persisted in the same transaction as the entity changes允许无限次重试。

  2. 在这里消除了其他体系结构中导致不同步索引的事件,因为在重新索引之前 each entity instance is reloaded from the database within a new transaction

  3. 易于扩展:您可以通过提供 JSON 来轻松访问大多数 Elasticsearch 功能,即使 Hibernate Search 中没有提供这些功能。例如,请参阅 JSON-defined predicatesJSON-defined aggregationsleveraging advanced features with JSON manipulation

  4. 应用程序线程的开销最小:应用程序线程 only need to append events to the queue,它们不会自己执行重新索引。

  5. 索引的水平可扩展性:您可以根据需要调整 Elasticsearch 集群的大小。请参阅 "Scalability and resilience" in the Elasticsearch documentation

  6. 应用程序的水平可扩展性:您可以拥有任意数量的应用程序实例。

缺点:

  1. 需要管理一个附加服务:Elasticsearch 集群。

  2. 索引更新的可见性延迟(~1 秒或更多,取决于负载和硬件)。一方面是因为 Elasticsearch 属于 near-real-time,另一方面是因为 the event queue introduces additional delays

  3. 对数据库模式的影响: additional tables must be created in the database持有协调所需的数据。

  4. 数据库的开销:读取实体更改并执行重新索引 needs to read changed entities from the database的后台进程。

Getting started

outbox-polling 协调策略需要额外的依赖关系。若要实现此架构,请使用以下 Maven 依赖项:

<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-mapper-orm</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>
<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-mapper-orm-outbox-polling</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>
<dependency>
   <groupId>org.hibernate.search</groupId>
   <artifactId>hibernate-search-backend-elasticsearch</artifactId>
   <version>7.2.0.Alpha2</version>
</dependency>

With the Standalone POJO Mapper (no Hibernate ORM)

目前,这种架构无法使用独立 POJO 映射器实现,因为此映射器 does not support coordination