我们针对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
}
}
}
}
}
最佳答案
这是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中的功能。