首页 > 解决方案 > 使用模糊性和 shingle 分析器使用 matchQuery 进行 Elasticsearch 搜索

问题描述

我正在使用elasticsearch并提出了这样的问题。我定义了一个带瓦类型的分析器并创建了一个映射。

这是代码:

{
    "settings": {
        "analysis": {
            "char_filter": {
                "icons": {
                    "type": "mapping",
                    "mappings_path": "analysis/char_filter.txt"
                }
            },
            "filter": {
                "synonym_filter": {
                    "type": "synonym",
                    "synonyms_path": "analysis/synonym_filter.txt"
                },
                "shingle_filter":{
                    "type":"shingle",
                    "max_shingle_size": 2,
                    "min_shingle_size": 2,
                    "output_unigrams": true,
                    "token_separator": ""
                }
            },
            "analyzer": {
                "my_analyzer": {
                    "filter": [
                        "lowercase",
                        "synonym_filter",
                        "shingle_filter"
                    ],
                    "char_filter": [
                        "icons"
                    ],
                    "tokenizer": "standard"
                }
            }
        }
    },
    "mappings": {
        "type-0": {
            "properties": {
                "text": {
                    "type": "text",
                    "analyzer": "my_analyzer"
                }
            }
        }
    }
}

然后,我将一个文档放入索引中。

{
   "text":"hello"
}

在此之后,我开始像这样搜索:

{
    "query":{
        "match":{
            "text":{
                "query":"hell world",
                "fuzziness":1
            }  
        }
    }
}

但它什么都不匹配。然后我将查询更改为:

{
    "query":{
        "match":{
            "text":{
                "query":"world hell",
                "fuzziness":1
            }  
        }
    }
}

这个请求得到文件。

{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.21576157,
        "hits": [
            {
                "_index": "index-001",
                "_type": "product",
                "_id": "1",
                "_score": 0.21576157,
                "_source": {
                    "text": "hello"
                }
            }
        ]
    }
}

我的弹性搜索版本是 6.2.4

谁能告诉我原因?

kibana 中的条件

分析地狱世界的结果

分析地狱的结果

分析世界地狱的结果

分析hello的结果

标签: elasticsearch

解决方案


fuzziness结合shingle_filter导致问题。如果您在匹配查询中阅读了模糊性的注释

模糊匹配不适用于具有同义词的术语或分析过程在同一位置产生多个标记的情况。 在幕后,这些术语被扩展为一个特殊的同义词查询,它混合了术语频率,它不支持模糊扩展。

注意粗体部分,同一位置的token不做模糊处理

现在让我们检查为您的搜索词生成的令牌hell world

{
    "tokens": [
        {
            "token": "hell",
            "start_offset": 0,
            "end_offset": 4,
            "type": "<ALPHANUM>",
            "position": 0 // position 0 for hell
        },
        {
            "token": "hellworld",
            "start_offset": 0,
            "end_offset": 10,
            "type": "shingle",
            "position": 0,  // again position 0 for 
            "positionLength": 2 
        },
        {
            "token": "world",
            "start_offset": 5,
            "end_offset": 10,
            "type": "<ALPHANUM>",
            "position": 1    //position 1 
        }
    ]
}

因此,对于位置 0 标记hellhellworld模糊性将不会被应用,因此它与索引标记不匹配hello并且不返回任何结果。

现在检查令牌world hell

{
    "tokens": [
        {
            "token": "world",
            "start_offset": 0,
            "end_offset": 5,
            "type": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "worldhell",
            "start_offset": 0,
            "end_offset": 10,
            "type": "shingle",
            "position": 0,
            "positionLength": 2
        },
        {
            "token": "hell",
            "start_offset": 6,
            "end_offset": 10,
            "type": "<ALPHANUM>",
            "position": 1   // this hell position is unique as 1 so it fuzziness will be applied.
        }
    ]
}

现在,当您使用 查询时world hell,将应用 onhell标记fuzziness,它将匹配hello索引标记并返回搜索结果。

您可以再次将搜索词更改为world hell elasticso nowhell不会有唯一的位置,因此它不会再次带来搜索结果。希望这将清除您的概念。


推荐阅读