匹配查询不返回完全匹配作为第一行

时间:2019-07-25 03:11:07

标签: elasticsearch

我在Elasticsearch中有数据,字段为fullName

  1. John Doe Doe
  2. John Doe
  3. 埃里克·约翰·多伊

当我针对fullName进行匹配查询时,使用此查询

{
    "from": 0,
    "size": 20,
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "fullName": {
                            "query": "John Doe",
                            "operator": "AND",
                            "fuzziness": "AUTO"
                        }
                    }
                }
            ]
        }
    }
}

我希望得到John Doe(完全匹配)作为第一个结果。 而是,返回值按以下顺序进行:

  1. John Doe Doe
  2. 埃里克·约翰·多伊
  3. John Doe

精确匹配的结果最低。

我该怎么做才能将完全匹配放入第一个结果? 我无法使用term查询,因为我仍然需要对fullName进行模糊匹配

谢谢

1 个答案:

答案 0 :(得分:1)

顺序错误是由于两个明显的问题。

修复第二个和第三个文档的顺序

第二个和第三个文档之间的顺序错误可能是由于分片。如果您使用单个分片,则会得到以下顺序:

  • John Doe Doe
  • John Doe
  • 埃里克·约翰·多伊

您可以阅读this article并解释原因。但是,如果每个分片中都有许多文档,则不应有此问题。如果要确保统计信息总是正确,则可以在搜索查询参数中使用_search?search_type=dfs_query_then_fetch

修复第一个和第二个文档的顺序

这有点棘手。默认的 elasticsearch相似性(即BM25)将在一个术语多次出现的情况下提高得分。在您的情况下,“母鹿”出现两次,因此其得分更高。要更改此行为,您必须使用custom similarity

您有两种解决方案:

  • 根据现有相似度写一个scripted similarity,以放弃重复条款的重要性
  • 配置默认的BM25相似度以降低重复条款的重要性

要在现有索引上创建自定义相似性,您必须:

  • close the index
  • 使用_settings端点添加相似性。
  • 重新打开索引

您还可以在创建索引时添加相似性。在示例中,我将始终创建一个新索引。

使用相似性,您可以将其设置为default similarity,也可以专门使用相似性来创建子字段。请注意,更改默认相似度会影响索引中的所有查询。对于您而言,我认为创建子字段更好。

解决方案1:创建脚本相似度

使用此解决方案,您将使用脚本化相似性来丢弃重复项的影响。该脚本基于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”的得分相同。

解决方案2:配置BM25相似性

您可以通过配置BM25 similarity来更改相似性行为。它具有2个参数k1b

  • 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,则在计算分数时,重复的术语和术语数将被丢弃。您的第一份和第二份文档的分数相同,顺序是随机的。