我在Elasticsearch中有数据,字段为fullName
:
当我针对fullName
进行匹配查询时,使用此查询
{
"from": 0,
"size": 20,
"query": {
"bool": {
"must": [
{
"match": {
"fullName": {
"query": "John Doe",
"operator": "AND",
"fuzziness": "AUTO"
}
}
}
]
}
}
}
我希望得到John Doe
(完全匹配)作为第一个结果。
而是,返回值按以下顺序进行:
精确匹配的结果最低。
我该怎么做才能将完全匹配放入第一个结果?
我无法使用term
查询,因为我仍然需要对fullName
进行模糊匹配
谢谢
答案 0 :(得分:1)
顺序错误是由于两个明显的问题。
第二个和第三个文档之间的顺序错误可能是由于分片。如果您使用单个分片,则会得到以下顺序:
您可以阅读this article并解释原因。但是,如果每个分片中都有许多文档,则不应有此问题。如果要确保统计信息总是正确,则可以在搜索查询参数中使用_search?search_type=dfs_query_then_fetch
。
这有点棘手。默认的 elasticsearch相似性(即BM25)将在一个术语多次出现的情况下提高得分。在您的情况下,“母鹿”出现两次,因此其得分更高。要更改此行为,您必须使用custom similarity。
您有两种解决方案:
要在现有索引上创建自定义相似性,您必须:
_settings
端点添加相似性。您还可以在创建索引时添加相似性。在示例中,我将始终创建一个新索引。
要使用相似性,您可以将其设置为default similarity,也可以专门使用相似性来创建子字段。请注意,更改默认相似度会影响索引中的所有查询。对于您而言,我认为创建子字段更好。
使用此解决方案,您将使用脚本化相似性来丢弃重复项的影响。该脚本基于TFIDF。
PUT /<INDEX>
{
"settings": {
"index": {
"similarity": {
"scripted_tfidf": {
"type": "scripted",
"script": {
"source": "return query.boost * (Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0) / Math.sqrt(doc.length);"
}
}
}
}
},
"mappings": {
"properties": {
"fullName": {
"type": "text",
"fields": {
"custom_similarity": {
"type": "text",
"similarity": "scripted_tfidf"
}
}
}
}
}
}
TFIDF是已弃用的相似性,但是由于其具有重复术语的行为而已弃用。由于我们消除了重复条款的影响,所以很好。
因为重复的术语被完全丢弃,所以使用这种解决方案时,精确匹配始终是第一个,但是“ John Doe Doe”和“ Eric John Doe”的得分相同。
您可以通过配置BM25 similarity来更改相似性行为。它具有2个参数k1
和b
。
k1
:定义对重复术语的重视程度。您想降低此值; b
:定义术语数量的重要性。您想增加此值。PUT /<INDEX>
{
"settings": {
"index": {
"similarity": {
"bm_25_custom": {
"type": "BM25",
// Update k1 and b values for bm25
"k1": "0.1",
"b": "1.0"
}
}
}
},
"mappings": {
"properties": {
"fullName": {
"type": "text",
"fields": {
// Add a subfield using the similarity defined previously
"custom_similarity": {
"type": "text",
"similarity": "bm_25_custom"
}
}
}
}
}
}
k1 = 0
,则在计算分数时,重复的术语和术语数将被丢弃。您的第一份和第二份文档的分数相同,顺序是随机的。