如何在使用HibernateSearch QueryDSL构建的Elasticsearch查询中包含prefixLength

问题描述 投票:0回答:1

我们在Elasticsearch 5.6.6服务器上使用Hibernate Search 5.10.3.Final。

在创建模糊查询以传递给FullTextSession :: createFullTextQuery时,我正在设置editDistance和prefixLength,但我从日志中注意到发送到Elasticsearch的实际查询不包含prefixLength。

此代码是从许多单独的方法中获取的,但这是基本的工作流程:

QueryBuilder qb = fts.getSearchFactory()
    .buildQueryBuilder()
    .forEntity(Vendor.class)
    .get();

BooleanJunction namesBool = qb.bool();

String field = "vendorNames.vendorName";
String token = "rooster";

int editDistance = getEditDistance(token); //returns 1 for "rooster"
int prefixLength = getPrefixLength(token); //returns 1 for "rooster"

namesBool.must(
    qb.keyword()
        .fuzzy() //returns FuzzyContext
        .withEditDistanceUpTo(editDistance)
        .withPrefixLength(prefixLength)
        .onField(field)
        .matching(token)
        .createQuery()
);


// ...
// calling FullTextSession::createFullTextQuery

当通过此方法发送术语“公鸡”时,它的editDistance(模糊性)为1,前缀长度为1。

检查日志并查看发送给ES的内容,我希望在“模糊”下面看到“prefix_length”,但它不存在:

{
  "query": {
    "bool": {
      "must": {
        "match": {
          "vendorNames.vendorName": {
            "query": "rooster",
            "fuzziness": 1
          }
        }
      }
    }
  }
  1. 为什么FuzzyContext允许设置prefixLength但不使用它?
  2. 尝试包含prefixLength是否真的值得ES性能提升(我使用和不使用prefixLength直接测试了REST查询调用,并且没有注意到响应时间差异)?
  3. 如何将prefixLength包含在发送给ES的实际查询中?
java elasticsearch hibernate-search
1个回答
1
投票

为什么FuzzyContext允许设置prefixLength但不使用它?

这是Elasticsearch集成的一个错误,但直到现在才报告:谢谢!我们将在下一个开发周期中尝试修复它:HSEARCH-3545

尝试包含prefixLength是否真的值得ES性能提升(我使用和不使用prefixLength直接测试了REST查询调用,并且没有注意到响应时间差异)?

prefixLength更多地是关于结果的相关性而不是性能。这个想法是,如果用户给我们一个10个字符长的单词,我们可能会得到很多模糊匹配,其中大部分都可能无关紧要。通过忽略前5个字符(例如),我们将把模糊性集中在单词的末尾附近,这可能不太相关(想想“理论”/“理论”,“构成”/“构成”等):这样我们将获得较少的模糊匹配,但它们将更具相关性。

至少那是理论:)

如何将prefixLength包含在发送给ES的实际查询中?

如果您不需要支持多个令牌,可以直接创建FuzzyQuery

BooleanJunction namesBool = qb.bool();
String field = "vendorNames.vendorName";
String token = "rooster";
int editDistance = getEditDistance(token); //returns 1 for "rooster"
int prefixLength = getPrefixLength(token); //returns 1 for "rooster"

namesBool.must(
    new FuzzyQuery(new Term(field, token), editDistance, prefixLength)
);

此查询将被正确翻译。

如果您确实需要支持多个令牌(即您需要fuzzy match query,而不仅仅是fuzzy query),那么您唯一的解决方案是将整个查询编写为JSON并使用org.hibernate.search.elasticsearch.ElasticsearchQueries#fromJson

String field = "vendorNames.vendorName";
String token = "rooster";
int editDistance = getEditDistance(token); //returns 1 for "rooster"
int prefixLength = getPrefixLength(token); //returns 1 for "rooster"

QueryDescriptor queryDescriptor = ElasticsearchQueries.fromJson(
"{"
  + "\"query\": {"
    + "\"bool\": {"
      + "\"must\": {"
        + "\"match\": {"
          + "\"" + field + "\": {"
            + "\"query\": \"" + token + "\","
            + "\"fuzziness\": " + editDistance + ","
            + "\"prefix_length\": " + prefixLength
          + "}"
        + "}"
      + "}"
    + "}"
  + "}"
+ "}"
);

List<?> result = session.createFullTextQuery( queryDescriptor, MyEntity.class )
                .list();

是的,它是满口的...我们正在改进Hibernate Search 6中的东西。

© www.soinside.com 2019 - 2024. All rights reserved.