首页 > 解决方案 > Hibernate Search:Elasticsearch 和 Lucene 产生不同的搜索结果

问题描述

我正在尝试使用 Spring Data Rest 和 Hibernate Search 为我的 REST 后端实现一个非常基本的搜索功能。我想允许用户通过将查询字符串传递给搜索函数来执行任意查询。为了能够更轻松地在本地运行后端并避免启动 Elasticsearch 来运行测试,我希望能够在这些情况下使用本地索引。

我的问题是,与 Elasticsearch 相比,使用本地索引的以下代码不会产生相同的结果。我试图将以下代码限制在我认为相关的范围内。

实体:

@Indexed(index = "MyEntity")
@AnalyzerDef(name = "ngram",
    tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class ),
    filters = {
      @TokenFilterDef(factory = StandardFilterFactory.class),
      @TokenFilterDef(factory = LowerCaseFilterFactory.class),
      @TokenFilterDef(factory = StopFilterFactory.class),
      @TokenFilterDef(factory = NGramFilterFactory.class,
        params = {
          @Parameter(name = "minGramSize", value = "2"),
          @Parameter(name = "maxGramSize", value = "3") } )
    }
)
public class MyEntity {

    @NotNull
    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.YES, analyzer = @Analyzer(definition = "ngram"))
    private String name;

    @Field(analyze = Analyze.YES, store = Store.YES)
    @FieldBridge(impl = StringCollectionFieldBridge.class)
    @ElementCollection(fetch = FetchType.EAGER)
    private Set<String> tags = new HashSet<>();

}

本地索引的 application.yml:

spring: 
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: false

用于 Elasticsearch 的 application.yml:

spring: 
  jpa:
    hibernate:
      ddl-auto: create-drop
    properties:
      hibernate:
        search:
          default:
            indexmanager: elasticsearch
            elasticsearch:
              host: 127.0.0.1:9200
              required_index_status: yellow

搜索端点:

private static String[] FIELDS = { "name", "tags" };

@Override
public List<MyEntity> querySearch(String queryString) throws ParseException {
    QueryParser queryParser = new MultiFieldQueryParser(FIELDS, new SimpleAnalyzer());
    queryParser.setDefaultOperator(QueryParser.AND_OPERATOR);
    org.apache.lucene.search.Query query = queryParser.parse(queryString);

    FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(this.entityManager);

    javax.persistence.Query persistenceQuery = 
            fullTextEntityManager.createFullTextQuery(query, MyEntity.class);

    return persistenceQuery.getResultList();
}

我创建了一个具有以下值的 MyEntity 实例:

$ curl 'localhost:8086/myentities'
{
  "_embedded" : {
    "myentities" : [ {
      "name" : "Test Entity",
      "tags" : [ "bar", "foobar", "foo" ],
      "_links" : {
        ...
      }
    } ]
  },
  "_links" : {
    ...
  }
}

以下查询使用 Elasticsearch 工作(返回该实体):

使用本地索引,我得到了“tags:bar:”的结果,但是对 name 字段的查询没有返回结果。任何想法为什么会这样?

标签: elasticsearchlucenehibernate-search

解决方案


您应该确保 Hibernate Search 正确创建了 Elasticsearch 映射。默认情况下,Hiberante Search 只会在缺少映射时创建映射。

如果您启动了一次应用程序,然后更改了映射,然后再次启动了应用程序,则该name字段可能在 Elasticsearch 中不正确。

在开发模式下,试试这个:

spring: 
  jpa:
    hibernate:
      ddl-auto: create-drop
    properties:
      hibernate:
        search:
          default:
            indexmanager: elasticsearch
            elasticsearch:
              host: 127.0.0.1:9200
              required_index_status: yellow
              index_schema_management_strategy: drop-and-create-and-drop

请参阅https://docs.jboss.org/hibernate/search/5.11/reference/en-US/html_single/#elasticsearch-schema-management-strategy

请注意,不幸的是,成功索引文档并不表示您的映射是正确的:当您尝试索引未知字段并试图猜测其类型时,Elasticsearch 甚至会动态创建字段(通常是错误的,在文本字段的情况下......)。您可以使用validate索引管理策略来确保在引导时,Elasticsearch 映射与 Hibernate Search 同步。


推荐阅读