【问题标题】:Elasticsearch search with matchQuery using fuzziness and shingle analyzer使用模糊性和 shingle 分析器使用 matchQuery 进行 Elasticsearch 搜索
【发布时间】:2020-11-15 17:10:33
【问题描述】:

我正在使用 elasticsearch 并提出了这样一个问题。 我定义了一个 analyzer 类型为 shingle 并创建了一个映射。

代码如下:

{
    "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"
                }
            }
        ]
    }
}

我的 elasticsearch 版本是 6.2.4

谁能告诉我原因?

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    fuzzinessshingle_filter 的组合导致了该问题。如果您阅读了来自fuzziness in match query的注释

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

    注意加粗部分,同一位置的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 进行查询时,hell 上的标记fuzziness 将被应用,它会匹配hello 索引标记并返回搜索结果。

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

    【讨论】:

    • analysis/char_filter.txtanalysis/synonym_filter.txt 这两个文件完全是空的。我尝试仅使用lowercaseshingle_analyzer 来定义my_analyzer。分析仪运行良好。我使用了analyze api并得到了和你一样的结果。但是搜索结果还是和以前一样。它无法命中带有hell world 的文档。您是如何管理代码的?
    • @Phoenix,我没有使用代码来获取搜索结果,我只是使用 JSON 格式的搜索查询(在我的答案中提供)请尝试对您的数据进行此查询,看看您是否得到搜索结果。
    • 我使用 kibana 开发工具 发送 JSON 格式的搜索请求。我尝试使用分析 API 获取令牌。它按预期返回三个令牌hellhellworldworld。但是当我使用搜索 API 时,它什么也不返回。我将搜索分析器更改为standard,它击中了文档。所以我现在真的很困惑。
    • @Phoenix,您能否再次提供您删除的 kibana dev-tools 的屏幕截图,我想我在这里遇到了问题,您刚刚索引了一个包含 hello 的文档并尝试搜索hell worldworld hell,您只需要拥有正确的索引文档,即hello world 而不是hell worldworld hell 两个搜索查询都有效
    • 我又发了截图。
    猜你喜欢
    • 2023-04-06
    • 2016-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-23
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多