Hibernate Search 中文操作指南

13. Managing the index schema

13.1. Basics

在使用索引建立索引或搜索之前,必须在磁盘(Lucene)或远程群集(Elasticsearch)中创建这些索引。尤其是对于 Elasticsearch,这种创建可能并不明显,因为它需要描述每个索引的架构,尤其是包括:

  1. 此索引中使用的每个分析器或规范器的定义;

  2. 此索引中使用的每个字段的定义,特别是包括其类型、分配给它的分析器、是否需要文档值等。

Hibernate Search 具有生成此架构所需的所有必要信息,因此可以将管理架构的任务委托给 Hibernate Search。

13.2. Automatic schema management on startup/shutdown

可以将属性 hibernate.search.schema_management.strategy 设置为以下值之一,以便定义在启动和关闭时对索引及其架构执行的操作。

Strategy

Definition

Warnings

none

启动或关闭时不执行任何操作的策略。索引及其架构不会在启动或关闭时创建或删除。Hibernate Search 会 not even check 索引实际上存在。

对于 Elasticsearch,索引及其架构必须在启动前显式创建。

validate

一种策略,该策略不更改索引或其架构,但会在启动时检查索引是否存在并验证其架构。如果发生以下情况,将在启动时抛出异常:缺失索引;或在只有 Elasticsearch 后端的情况下,索引存在但其架构不满足 Hibernate Search 映射的要求:缺少字段,字段类型错误,缺少分析器定义或标准化器定义, …​​​“兼容”差异,例如额外的字段 are ignored

在启动之前必须明确创建索引及其架构。在 Lucene 后端,验证仅限于检查索引是否存在,因为 local Lucene indexes don’t have a schema

create

在启动时创建丢失的索引及其架构,但不会接触现有索引,并假设其架构正确而无需验证的策略。

Creating a schema does not populate indexed data

create-or-validate (default)

一种策略,该策略会在启动时创建缺失的索引及其架构,并验证现有索引的架构。仅在 Elasticsearch 后端,如果某些索引已经存在,但其架构不满足 Hibernate Search 映射的要求,将在启动时抛出异常:缺少字段,字段类型错误,缺少分析器定义或标准化器定义, …​​​“兼容”差异,例如额外的字段 are ignored

Creating a schema does not populate indexed data。在 Lucene 后端,验证仅限于检查索引是否存在,因为 local Lucene indexes don’t have a schema

create-or-update

一个策略,在启动时创建缺失的索引及它们的架构,并在可能的情况下更新现有索引的架构。

Updating a schema does not update indexed dataThis strategy is unfit for production environments,由于包括 the impossibility to change the type of an existing fieldthe requirement to close indexes while updating analyzer definitions在内的几个限制(在 AWS 上根本不可用)。在 Lucene 后端,架构更新是不操作的,因为 local Lucene indexes don’t have a schema

drop-and-create

一个策略,丢弃现有索引并在启动时重新创建它们及它们的架构。

All indexed data will be lost启动时。

drop-and-create-and-drop

一个策略,丢弃现有索引并在启动时重新创建它们及它们的架构,然后在关闭时丢弃索引。

All indexed data will be lost启动和关闭时。

13.3. Manual schema management

架构管理不必在启动和关闭时自动进行。

使用 SearchSchemaManager 接口,可以在 Hibernate Search 启动后显式触发架构管理操作。

最常见的用例是将 automatic schema management strategy 设置为 none ,并在满足某些其他条件(例如 Elasticsearch 集群已完成引导)时手动处理索引的创建/删除。

在模式管理操作完成后,通常需要填充索引。为此,请使用 mass indexer

SearchSchemaManager 接口公开以下方法。

Method

Definition

Warnings

validate()

不更改索引及其架构,但检查索引是否存在并验证其架构。

在 Lucene 后端,验证仅限于检查索引是否存在,因为 local Lucene indexes don’t have a schema

createIfMissing()

创建缺失的索引及它们的架构,但不触碰现有索引并假设它们的架构是正确的,无需对其进行验证。

Creating a schema does not populate indexed data

createOrValidate()

创建缺失的索引及它们的架构,并验证现有索引的架构。

Creating a schema does not populate indexed data。在 Lucene 后端,验证仅限于检查索引是否存在,因为 local Lucene indexes don’t have a schema

createOrUpdate()

创建缺失索引及其架构,如果可能,更新已有索引的架构。

1、借助 Elasticsearch 后端,2、借助 Elasticsearch 后端,3、(这在 4 中完全不可能)。借助 Lucene 后端,架构更新为无操作,原因是 5。(它只创建缺失的索引)。

dropIfExisting()

Drops existing indexes.

6、

dropAndCreate()

丢弃现有索引并重新创建它们及其架构。

6、

以下是使用 SearchSchemaManager 删除和创建索引,然后使用 mass indexer 重新填充索引的示例。 dropAndCreateSchemaOnStart setting of the mass indexer 是实现相同结果的替代解决方案。

示例 137。使用 SearchSchemaManager 重新初始化索引
SearchSession searchSession = /* ... */ (1)
SearchSchemaManager schemaManager = searchSession.schemaManager(); (2)
schemaManager.dropAndCreate(); (3)
searchSession.massIndexer()
        .purgeAllOnStart( false )
        .startAndWait(); (4)

在创建架构管理器时,还可以选择实体类型,以仅管理这些类型的索引(及其已编入索引的子类型(如果存在)):

示例 138。仅使用 SearchSchemaManager 重新初始化部分索引
SearchSchemaManager schemaManager = searchSession.schemaManager( Book.class ); (1)
schemaManager.dropAndCreate(); (2)

13.4. How schema management works

Creating/updating a schema does not create/update indexed data

通过架构管理创建或更新索引及其架构不会填充索引:

新创建的索引将始终为空。

具有最近更新架构的索引仍将包含相同的已编制索引数据,即不会将新字段添加到文档中,仅仅因为它们已添加到架构中。

这是设计使然:重新索引是一项潜在的长时间运行的任务,应明确触发。要使用数据库中的已存在数据填充索引,请使用 mass indexing

Dropping the schema means losing indexed data

删除架构将删除整个索引,包括所有已索引数据。

已删除的索引需要通过模式管理重新创建,然后通过 mass indexing使用来自数据库中的已存在数据填充。

Schema validation and update are not effective with Lucene

Lucene 后端只会验证索引实际存在并创建缺失的索引,因为在 Lucene 中没有架之外的概念。

Schema validation is permissive

使用 Elasticsearch,架构验证尽可能宽松:

将忽略 Hibernate Search 未知的字段。

比需要更强大的设置将被认为有效。例如,在 Hibernate Search 中未标记为可排序但 Elasticsearch 中标记为 _"docvalues": true_的字段将被视为有效。

将忽略 Hibernate Search 未知的分析器/规范器定义。

一个例外:由于实现限制,日期格式必须与 Hibernate Search 指定的格式完全匹配。

Schema updates may fail

create-or-update 策略触发的架构更新可能会失败。这是因为架构可能会以不兼容的方式更改,例如字段的类型改变或分析器改变等。

更糟糕的是,由于更新是按索引进行处理的,因此某个索引的架构更新可能成功,但另一个索引的更新可能失败,从而导致整个架构处于半更新状态。

由于这些原因,不建议在生产环境中使用架构更新。每当架构发生变化时,你应该:

删除并创建索引,然后 reindex

或通过自定义脚本手动更新架构。

在这种情况下,create-or-update 策略将阻止 Hibernate Search 启动,但该策略可能已成功地为另一个索引更新了架构,从而导致回滚变得困难。

Schema updates on Elasticsearch may close indexes

Elasticsearch 不允许在开放索引中更新分析器/规范化器定义。因此,当在架构更新期间必须更新分析器或规范化器定义时,Hibernate Search 将暂时停止受影响的索引。

因此,当多个客户端使用由 Hibernate Search 管理的 Elasticsearch 索引时,应谨慎使用 create-or-update 策略:应以这种方式同步这些客户端,使得在 Hibernate Search 启动时,没有其他客户端需要访问索引。

此外,在 Amazon OpenSearch Service 运行 Elasticsearch(不是 OpenSearch)7.1 或更低版本以及 Amazon OpenSearch Serverless 中,不支持 close / open 操作,所以在尝试更新分析器定义时架构更新将失败。唯一的解决方法是避免在这些平台上进行架构更新。无论如何,在生产环境中都应该避免:请参见 [schema-management-concepts-update-failure]

13.5. Exporting the schema

13.5.1. Exporting the schema to a set of files

schema manager提供了一种将模式导出到文件系统的方法。输出是后端特定的。

模式导出是根据映射信息和配置(例如后端版本)构建的。生成的结果不会与实际后端模式进行比较或与之验证。

对于 Elasticsearch,文件提供创建索引(及其设置和映射)所需的信息。导出的文件树结构如下所示:

# For the default backend the index schema will be written to:
.../backend/indexes/<index-name>/create-index.json
.../backend/indexes/<index-name>/create-index-query-params.json
# For additional named backends:
.../backends/<name of a particular backend>/indexes/<index-name>/create-index.json
.../backends/<name of a particular backend>/indexes/<index-name>/create-index-query-params.json
示例 139. 将架构导出到文件系统
SearchSchemaManager schemaManager = searchSession.schemaManager(); (1)
schemaManager.exportExpectedSchema( targetDirectory ); (2)

13.5.2. Exporting to a custom collector

Search schema managers允许根据此类管理器包含的数据遍历模式导出。要执行此操作,必须实现一个 _SearchSchemaCollector_并将其传递给模式管理器的 _exportExpectedSchema(..)_方法。

模式导出是根据映射信息和配置(例如后端版本)构建的。生成的结果不会与实际后端模式进行比较或与之验证。

示例 140. 导出到自定义收集器
SearchSchemaManager schemaManager = searchSession.schemaManager(); (1)
schemaManager.exportExpectedSchema(
        new SearchSchemaCollector() { (2)
            @Override
            public void indexSchema(Optional<String> backendName, String indexName, SchemaExport export) {
                String name = backendName.orElse( "default" ) + ":" + indexName; (3)
                // perform any other actions with an index schema export
            }
        }
);

要访问后端特定的功能,可应用对 SchemaExport 的扩展:

_new SearchSchemaCollector() {

    @Override
    public void indexSchema(Optional<String> backendName, String indexName, SchemaExport export) {
        List<JsonObject> bodyParts = export
                .extension( ElasticsearchExtension.get() ) (1)
                .bodyParts(); (2)
    }
}_1Extend the _SchemaExport_ with the Elasticsearch extension.2Access an HTTP body of a request that is needed to create an index in an Elasticsearch cluster.
_new SearchSchemaCollector() {
    @Override
    public void indexSchema(Optional<String> backendName, String indexName, SchemaExport export) {
        List<JsonObject> bodyParts = export
                .extension( ElasticsearchExtension.get() ) (1)
                .bodyParts(); (2)
    }
}_1Extend the _SchemaExport_ with the Elasticsearch extension.2Access an HTTP body of a request that is needed to create an index in an Elasticsearch cluster.
_new SearchSchemaCollector() {
    @Override
    public void indexSchema(Optional<String> backendName, String indexName, SchemaExport export) {
        List<JsonObject> bodyParts = export
                .extension( ElasticsearchExtension.get() ) (1)
                .bodyParts(); (2)
    }
}_
_new SearchSchemaCollector() {
    @Override
    public void indexSchema(Optional<String> backendName, String indexName, SchemaExport export) {
        List<JsonObject> bodyParts = export
                .extension( ElasticsearchExtension.get() ) (1)
                .bodyParts(); (2)
    }
}_
1Extend the _SchemaExport_ with the Elasticsearch extension.2Access an HTTP body of a request that is needed to create an index in an Elasticsearch cluster.

13.5.3. Exporting in offline mode

有时,从无法访问 Elasticsearch 集群(例如)的环境中离线导出架构非常有用。

有关如何实现脱机启动的更多信息,请参见 this section