首页 > 解决方案 > Elasticsearch 部分匹配成功,完全匹配失败

问题描述

我的用户索引的“句柄”字段中有一个值。假设这个值的确切字符串是“exactstring”。我的查询将为“exactstrin”返回正确的结果,但对于“exactstring”它将失败(不返回任何内容)。N-gram,如“actstr”,也返回正确的结果。怎么回事?

{
    "query": {
        "bool": {
            "must": [{
                "multi_match": {
                    "fields": ["handle","name","bio"],
                    "prefix_length": 2,
                    "query": "exacthandle",
                    "fuzziness": "AUTO"
                }
            }],
            "should" : [{
                "multi_match": {
                    "fields": ["handle^6", "name^3", "bio"],
                    "query": "exacthandle"
                }
            }]
        }
    },
    "size": 100,
    "from": 0
}

这是我的设置:

"settings": {
        "analysis": {
            "analyzer": {
                "search_term_analyzer": {
                    "type": "custom",
                    "stopwords": "_none_",
                    "filter": [
                        "standard",
                        "lowercase",
                        "asciifolding",
                        "no_stop"
                    ],
                    "tokenizer": "whitespace"
                },
                "ngram_token_analyzer": {
                    "type": "custom",
                    "stopwords": "_none_",
                    "filter": [
                        "standard",
                        "lowercase",
                        "asciifolding",
                        "no_stop",
                        "ngram_filter"
                    ],
                    "tokenizer": "whitespace"
                }
            },
            "filter": {
                "no_stop": {
                    "type": "stop",
                    "stopwords": "_none_"
                },
                "ngram_filter": {
                    "type": "nGram",
                    "min_gram": "2",
                    "max_gram": "9"
                }
            }
        }
    }

还有我的映射:

"handle": {
    "type": "text",
    "fields": {
        "keyword": {
            "type": "keyword",
            "ignore_above": 256
        }
    }
},
"name": {
    "type": "text",
    "fields": {
        "keyword": {
            "type": "keyword",
            "ignore_above": 256
        }
    }
},
"bio": {
    "type": "text",
    "fields": {
        "keyword": {
            "type": "keyword",
            "ignore_above": 256
        }
    }
}

标签: elasticsearch

解决方案


我最终使用多字段来解决这个问题。查询字段“handle.text”现在返回任意长度的精确字符串匹配。

我还能够创建具有不同最小和最大克数的 ngram 和 edge_ngram 过滤器,然后同时使用它们。

映射现在看起来像这样:

"handle": {
    "type": "text",
    "fields": {
    "keyword": {
      "type": "keyword",
      "ignore_above": 256
    },
    "text": {
      "type": "text"
    },
    "edge_ngram": { 
      "type": "text",
      "analyzer": "edge_ngram_token_analyzer"
    },
    "ngram": { 
      "type": "text",
      "analyzer": "ngram_token_analyzer"
    }
  }
}

多匹配查询现在可以在同一个字段上同时使用不同的分析器(必须和应该查询之间的巨大差异归结为模糊性,生物字段往往包含很多小标记,模糊性会产生很多坏命中) :

{
    "query": {
        "bool": {
            "must" : [{
                "multi_match": {
                    "fields": [
                        "handle.text^6", 
                        "handle.edge_ngram^4", 
                        "handle.ngram^2",
                        "bio.text^6", 
                        "bio.keyword^4",
                        "name.text^6", 
                        "name.keyword^5", 
                        "name.edge_ngram^2", 
                        "name.ngram^3"
                        ],
                    "query": "exactstring",
                    "prefix_length": 2
                }
            }],
            "should" : [{
                "multi_match": {
                    "fields": [
                        "handle.text^6", 
                        "handle.edge_ngram^2", 
                        "handle.ngram^1",
                        "name.text^6", 
                        "name.keyword^5", 
                        "name.edge_ngram^2", 
                        "name.ngram^3"
                        ],
                    "query": "exactstring",
                    "prefix_length": 2,
                    "fuzziness": "AUTO"
                }
            }]
        }
    },
    "size": 100,
    "from": 0
}

为了完整起见,这里是我的索引的设置:

"settings": {
        "analysis": {
            "analyzer": {
                "search_term_analyzer": {
                    "type": "custom",
                    "stopwords": "_none_",
                    "filter": [
                        "standard",
                        "lowercase",
                        "asciifolding",
                        "no_stop"
                    ],
                    "tokenizer": "whitespace"
                },
                "ngram_token_analyzer": {
                    "type": "custom",
                    "stopwords": "_none_",
                    "filter": [
                        "standard",
                        "lowercase",
                        "asciifolding",
                        "no_stop",
                        "ngram_filter"
                    ],
                    "tokenizer": "whitespace"
                },
                "edge_ngram_token_analyzer": {
                    "type": "custom",
                    "stopwords": "_none_",
                    "filter": [
                        "standard",
                        "lowercase",
                        "asciifolding",
                        "no_stop",
                        "edge_ngram_filter"
                    ],
                    "tokenizer": "whitespace"
                }
            },
            "filter": {
                "no_stop": {
                    "type": "stop",
                    "stopwords": "_none_"
                },
                "ngram_filter": {
                    "type": "nGram",
                    "min_gram": "3",
                    "max_gram": "12"
                },
                "edge_ngram_filter": {
                    "type": "edgeNGram",
                    "min_gram": "3",
                    "max_gram": "50"
                }
            }
        },
        "max_ngram_diff": 50
    }

h/t 到 @bhavya 获取 max_ngram_diff


推荐阅读