我们针对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,prefixLength为1。

检查日志并查看发送到ES的内容,我希望直接在“模糊性”下方看到“prefix_length”,但它不存在:
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "vendorNames.vendorName": {
            "query": "rooster",
            "fuzziness": 1
          }
        }
      }
    }
  }
  • FuzzyContext为什么允许设置prefixLength但不使用它?
  • 尝试包含prefixLength是否真的值得提高ES性能(我测试了是否在带和不带prefixLength的情况下直接对ES进行REST查询调用,并且没有注意到响应时间差)?
  • 如何才能将prefixLength包含在发送给ES的实际查询中?
  • 最佳答案



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


    prefixLength更加注重结果的相关性而不是性能。这个想法是,如果用户给我们一个10个字符长的单词,我们很可能会得到许多模糊匹配,其中大多数可能是不相关的。通过忽略前5个字符(例如),我们会将模糊性集中在单词的末尾,这可能不太相关(例如,“theory” /“theories”,“constituting” /“constitute”等):这样,我们将获得较少的模糊匹配,但它们将更相关。

    至少那是理论:)



    如果不需要支持多个 token ,则可以直接创建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)
    );
    

    该查询将被正确翻译。

    如果确实需要支持多个 token (即您需要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();
    

    是的,这令人a目结舌...我们正在改进Hibernate Search 6中的功能。

    09-26 00:17