Hibernate Search 中文操作指南

7. Standalone POJO Mapper

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

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

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

7.1. Basics

Standalone POJO Mapper 可以将任意 POJO 映射到索引。

Hibernate ORM integration 相比,它的一个主要特性就是它不需要 Hibernate ORM 或关系数据库即可运行。

它可用于索引来自任意数据存储的实体,甚至(虽然一般不建议这样做)将 Lucene 或 Elasticsearch 用作主数据存储。

由于 Standalone POJO Mapper 除了假设被映射的实体表示为 POJO 之外,不会对这些实体做任何假设,因此,使用它可能会比 Hibernate ORM integration 更加复杂。具体而言:

  1. 此映射器 cannot detect entity changes on its own:全部索引 must be explicit

  2. 必须 implemented in the application加载实体,以获取搜索结果中的命中。

  3. 必须 implemented in the application加载标识符和实体,以获取 mass indexing

  4. 此映射器目前 does not provide coordination between nodes

7.2. Startup

使用独立 POJO 映射器启动 Hibernate Search 是显式的并涉及一个构建器:

示例 1. 使用独立 POJO 映射器启动 Hibernate Search

借助 classpath scanning ,你的 AnnotatedTypeSource 只需要包含来自每个包含注解类型 JAR 的一个类。系统会自动发现其他类型。

还可以参阅 this section 以对类路径扫描进行故障排除或提高其性能。

7.3. Shutdown

您可以通过对映射调用 close() 方法来使用独立 POJO 映射器关闭 Hibernate Search:

示例 2. 使用独立 POJO 映射器关闭 Hibernate Search

CloseableSearchMapping searchMapping = /* ... */ (1)
searchMapping.close(); (2)

在关闭时,Hibernate Search 将停止接受新的索引请求:新的索引尝试将引发异常。close() 方法只会在所有正在进行的索引操作完成后返回。

7.4. Bean provider

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

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

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

Standalone POJO Mapper 可能涉及到 retrieve beans from CDI/Spring,但是需要通过 Bean 提供程序显式实现这一支持功能。

您可以分两步插入您自己的 bean 提供程序:

  • 定义一个实现 _org.hibernate.search.engine.environment.bean.spi.BeanProvider_接口的类。

  • 通过将配置属性 hibernate.search.bean_provider 设置为指向该实现的 bean reference,例如 class:com.mycompany.MyMappingConfigurer,来配置 Hibernate Search 使用该实现。显然,无法使用 bean 提供者解析对 bean 提供者的引用。

7.5. Multi-tenancy

在启动独立 POJO 映射器时需要显式启用多租户:

示例 3. 用 Standalone POJO 映射启用多租户
CloseableSearchMapping searchMapping = SearchMapping.builder( AnnotatedTypeSource.fromClasses( (1)
        Book.class
) )
        // ...
        .property( "hibernate.search.mapping.multi_tenancy.enabled", true ) (2)
        .build(); (3)

启用多租户后,在创建 SearchSession 和其他一些情况下(创建 mass indexer, workspace 等),必须提供租户 ID。

示例 4. 使用租户标识符创建 SearchSession
SearchMapping searchMapping = /* ... */ (1)
Object tenantId = "myTenantId";
try ( SearchSession searchSession = searchMapping.createSessionWithOptions() (2)
        .tenantId( tenantId ) (3)
        .build() ) { (4)
    // ...
}

在使用非字符串租户标识符时,必须提供一个自定义 TenantIdentifierConverter

_CloseableSearchMapping searchMapping = SearchMapping.builder( AnnotatedTypeSource.fromClasses( (1) Book.class) ) // …​ .property( "hibernate.search.mapping.multi_tenancy.enabled", true ) (2) .property( "hibernate.search.mapping.multi_tenancy.tenant_identifier_converter", new TenantIdentifierConverter() { @Override public String toStringValue(Object tenantId) { return tenantId == null ? null : tenantId.toString(); }

                    @Override
                    public Object fromStringValue(String tenantId) {
                        return tenantId == null ? null : UUID.fromString( tenantId );
                    }
                }
        ) (3)
        .build(); (4)_
_CloseableSearchMapping searchMapping = SearchMapping.builder( AnnotatedTypeSource.fromClasses( (1)
        Book.class
) )
        // ...
        .property( "hibernate.search.mapping.multi_tenancy.enabled", true ) (2)
        .property(
                "hibernate.search.mapping.multi_tenancy.tenant_identifier_converter",
                new TenantIdentifierConverter() {
                    @Override
                    public String toStringValue(Object tenantId) {
                        return tenantId == null ? null : tenantId.toString();
                    }
                    @Override
                    public Object fromStringValue(String tenantId) {
                        return tenantId == null ? null : UUID.fromString( tenantId );
                    }
                }
        ) (3)
        .build(); (4)_
1Create a builder.2Enable multi-tenancy.3Set a custom tenant identifier converter.4Build the _SearchMapping_.

7.6. Mapping

虽然 Hibernate ORM integration 可以从 Hibernate ORM 映射推断一部分映射,但是 Standalone POJO Mapper 不可以。因此,Standalone POJO Mapper 需要的映射明确配置更多:

  1. Entity types 必须是 defined explicitly

  2. 文档标识符必须是 mapped explicitly

  3. 关联的反向端必须是 mapped explicitly

7.7. Indexing

7.7.1. Listener-triggered indexing

Standalone POJO Mapper 不提供 Hibernate ORM integrationlistener-triggered indexing 类似的“隐式”索引。

相反,您必须用 indexing plan 显式进行索引。

7.7.2. Explicitly indexing on entity change events

Standalone POJO Mapper 可以处理实体更改事件(添加、更新、删除)并据此执行索引,但是必须明确将事件传递给 Hibernate Search。有关 API 的更多信息,请参见 Indexing plans

Hibernate ORM integration 的一个主要区别是:不支持事务(JTA 或其他事务),因此索引是在 session closing 上执行,而不是在事务提交时执行。

7.7.3. Mass indexing

由于默认情况下,Standalone POJO Mapper 不了解实体数据来自何处,因此 mass indexing 需要插入一种从其他数据存储 en masse 加载实体的方式:批量加载策略。

entity definition 的一部分中,将批量加载策略分配给 entity types:有关更多信息,请参阅 Mass loading strategy

7.7.4. Entity loading in search queries

因为默认情况下 Standalone POJO Mapper 不知道实体数据从哪里来,所以 entity loading in search queries 需要插入一种方法来从其他数据存储加载一系列实体:选择加载策略。

选择加载策略在 entity definition 的一部分中分配给 entity types:有关更多信息,请参阅 Selection loading strategy

对于 Standalone POJO 映射,如果你想从索引加载实体,而不是外部数据源,请向实体类型添加 projection constructor

如果缺失此部分中描述的配置并且必须进行加载(比如未在搜索查询中使用 select() ),这将自动导致从索引加载实体。

7.8. Coordination

Standalone POJO Mapper 目前不提供任何在节点之间进行协调的方法,所以它的行为大体上类似于 No coordination 中描述的行为,不同的是实体数据提取在会话关闭时发生,而不是在 Hibernate ORM 会话刷新时发生,索引在之后立即发生,而不是在事务提交时发生。

7.9. Reading configuration properties from a file

Standalone POJO Mapper SearchMappingBuilder 还可以从与 java.util.Properties#load(Reader) 兼容的 Reader 中获取属性:

示例 5. 使用 Reader 从文件中加载配置属性
try (
        Reader propertyFileReader = /* ... */ (1)
) {
    CloseableSearchMapping searchMapping = SearchMapping.builder( AnnotatedTypeSource.empty() ) (2)
            .properties( propertyFileReader ) (3)
            .build();
}

7.10. Other configuration

相关部分的文档中提到了其他配置属性。您可以在 the Standalone POJO Mapper configuration properties appendix 中找到可用属性的全部引用。