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

标签 java elasticsearch hibernate-search

我们正在针对 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

当术语“rooster”通过此方法发送时,它的 editDistance(模糊度)为 1,prefixLength 为 1。

检查日志并查看发送到 ES 的内容,我希望在“fuzziness”正下方看到“prefix_length”,但它不在那里:

{
  "query": {
    "bool": {
      "must": {
        "match": {
          "vendorNames.vendorName": {
            "query": "rooster",
            "fuzziness": 1
          }
        }
      }
    }
  }
  1. 为什么 FuzzyContext 允许设置 prefixLength 但不允许使用它?
  2. 尝试包含 prefixLength 是否真的值得提高 ES 性能(我测试了直接对 ES 进行 REST 查询调用,无论有没有 prefixLength,都没有注意到响应时间差异)?
  3. 如何将 prefixLength 包含在发送到 ES 的实际查询中?

最佳答案

Why does FuzzyContext allow for setting the prefixLength but not use it?

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

Is it really worth the ES performance increase to try to include prefixLength (I tested REST query calls directly to ES both with and without prefixLength and didn't notice a response time difference)?

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

至少理论上是这样:)

How can I get prefixLength to be included in the actual query sent to ES?

如果不需要支持多个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();

是的,有点拗口...我们正在改进 Hibernate Search 6 中的功能。

关于java - 如何在使用 HibernateSearch QueryDSL 构建的 Elasticsearch 查询中包含 prefixLength,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55403632/

相关文章:

java - 如何将 hibernate-search 与 JBoss datagrid 一起使用?

java - 如何在 Hibernate Search 中正确使用 @ContainedIn 注解?

python - Spark并没有采用所有索引内容

elasticsearch - Elastic Search中嵌套聚合的加权平均值

Java Flight Recorder 选项不起作用,文件仅存储在持续时间设置的末尾

java - findViewById() 无法在我的自定义适配器中解析

ruby-on-rails - Elasticsearch /轮胎 : How to map to association attribute?

java - Hibernate Search - MySQL 错误太多与连接继承模型连接

java - 如何在 Java 中正确覆盖 toString()?

java - 当多行作为 JTextarea 的输入时,如何在文件中写入多行?