我正在ElasticSearch中实现自动完成索引,并且遇到了排序/评分问题。假设索引中包含以下字符串:
apple banana coconut donut apple banana donut durian apple donut coconut durian donut banana coconut durian
当我搜索“甜甜圈”时,我希望结果按术语位置来排序,如下所示:
donut banana coconut durian apple donut coconut durian apple banana donut durian apple banana coconut donut
我不知道如何做到这一点。字词排名未纳入默认的评分逻辑,而且我找不到找到方法。似乎很简单,尽管以前其他人也必须遇到这个问题。有人知道吗?
谢谢!
根据安德烈(Andrei)的答案,这是我最终得到的解决方案,并扩展为支持多个搜索词和基于结果中第一个单词的长度的附加评分:
首先,定义以下自定义分析器(它将整个字符串保留为单个标记并将其小写):
"raw_analyzer": { "type": "custom", "filter": [ "lowercase" ], "tokenizer": "keyword" }
其次,像这样定义您的搜索字段映射(我的名为“ name”):
"name": { "type": "string", "analyzer": "english", "fields": { "raw": { "type": "string", "index_analyzer": "raw_analyzer", "search_analyzer": "standard" } } }, "_nameFirstWordLength": { "type": "long" }
第三,在填充索引时,请使用以下逻辑(在C#中为mine)填充:
_nameFirstWordLength = fi.Name.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries)[0].Length
最后,进行如下搜索:
{ "query":{ "bool":{ "must":{ "match_phrase_prefix":{ "name":{ "query":"apple" } } }, "should":{ "function_score":{ "query":{ "query_string":{ "fields":[ "name.raw" ], "query":"apple*" } }, "script_score":{ "script":"100/doc['_nameFirstWordLength'].value" }, "boost_mode":"replace" } } } } }
我正在使用match_phrase_prefix,以便支持部分匹配,例如“ ap”匹配“ apple”。布尔值必须/应该使用针对name.raw的第二个query_string查询来为名称以搜索项之一开头的结果赋予更高的分数(在我的代码中,我仅针对第二个查询对搜索字符串进行了预处理,在每个词后添加“ *”)。最后,将第二个查询包装在使用_nameFirstWordLength值的function_score脚本中,会导致第二个查询向上排序的结果按其第一个单词的长度进一步排序(例如,导致Apple在Applebee之前显示)。