我们正在针对 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
}
}
}
}
}
- 为什么 FuzzyContext 允许设置 prefixLength 但不允许使用它?
- 尝试包含 prefixLength 是否真的值得提高 ES 性能(我测试了直接对 ES 进行 REST 查询调用,无论有没有 prefixLength,都没有注意到响应时间差异)?
- 如何将 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/