如何使用spring-data和elasticsearch执行文本/短语搜索?

rryofs0p  于 2023-06-29  发布在  ElasticSearch
关注(0)|答案(1)|浏览(133)

我有一个索引与多个文本字段的文档。我想执行一个搜索,该搜索应匹配

  • 要么从那个确切的文本开始,
  • 要么包含 * 确切 * 文本,
  • 或以 * 确切 * 文本结尾

在一些预定义的字段上,以及另一个 * 静态 * 条件。
首先,我考虑使用queryStringQuery和通配符实现搜索

var queryBuilder = new BoolQueryBuilder();
queryBuilder
    .must(QueryBuilders.queryStringQuery(String.format("*%s*", QueryParser.escape(filterText)))
         .field(FIELD_1)
         .field(FIELD_2)
         .field(FIELD_3)
         .analyzeWildcard(true))
    .must(QueryBuilders.termQuery(FIELD_X, "...")));
var nativeQuery = new NativeSearchQueryBuilder().withQuery(queryBuilder).withPageable(pageable).build();
elasticsearchOperations.search(nativeReq, MyEntity.class);

只要filterText是一个单词,这个解决方案就可以正常工作,但是一旦默认/标准分析器标记文本,我就会得到意想不到的结果(对于我的用例)。
我一直在考虑使用短语查询进行搜索:

var queryBuilder = new BoolQueryBuilder();
var insideQuery = new BoolQueryBuilder();
insideQuery
    .should(QueryBuilders.matchPhraseQuery(FIELD_1, filterText))
    .should(QueryBuilders.matchPhraseQuery(FIELD_2, filterText))
    .should(QueryBuilders.matchPhraseQuery(FIELD_3, filterText));
queryBuilder
    .should(insideQuery).minimShouldMatch(1)
    .must(QueryBuilders.termQuery(FIELD_X, "...")));

但我还是得到了意想不到的结果。
我还尝试了一个与第一个类似的解决方案,并试图强制es使用keyword analyzer,但我没有设法这样做(0结果),也许是因为我的Map将字段定义为文本而不是关键字?!
您能否帮助我/为我指出一个与我的具体用例相匹配的解决方案?

8aqjt8rx

8aqjt8rx1#

我最终将字段类型从Text更改为Keyword,并调整代码如下:

var queryBuilder = new BoolQueryBuilder();

// match exact phrase using keyword analyzer
queryBuilder
    .should(QueryBuilders.matchPhraseQuery(FIELD_1, filterText).analyzer("keyword"))
    .should(QueryBuilders.matchPhraseQuery(FIELD_2, filterText).analyzer("keyword"))
    .should(QueryBuilders.matchPhraseQuery(FIELD_3, filterText).analyzer("keyword"));

// match beginning/end/middle of text with wildcard
var wildcardFilter = String.format("*%s*", filterText);
queryBuilder.
    .should(QueryBuilders.wildcardQuery(FIELD_1, wildcardFilter))
    .should(QueryBuilders.wildcardQuery(FIELD_2, wildcardFilter))
    .should(QueryBuilders.wildcardQuery(FIELD_3, wildcardFilter));

// at least one optional clause ("should") has to match 
queryBuilder.minimumShouldMatch(1);
queryBuilder.must(QueryBuilders.termQuery(FIELD_X, "...")));

在我测试的大多数情况下都很有效。
也许这不是实现这一目标的最佳方式,但它完成了工作。

相关问题