【问题标题】:How to make exact phrase matching in elastic search?如何在弹性搜索中进行精确的短语匹配?
【发布时间】:2019-02-11 21:18:49
【问题描述】:

我正在尝试在弹性搜索中实现完全匹配搜索。但我没有得到所需的结果。 这是解释我面临的问题和我尝试过的事情的代码。

doc1 = {"sentence": "Today is a sunny day."}
doc2 = {"sentence": " Today is a sunny day but tomorrow it might rain"}
doc3 = {"sentence": "I know I am awesome"}
doc4 = {"sentence": "The taste of your dish is awesome"}
doc5 = {"sentence": "The taste of banana shake is good"}

# Indexing the above docs

es.index(index="english",doc_type="sentences",id=1,body=doc1)

es.index(index="english",doc_type="sentences",id=2,body=doc2)

es.index(index="english",doc_type="sentences",id=3,body=doc3)

es.index(index="english",doc_type="sentences",id=4,body=doc4)

es.index(index="english",doc_type="sentences",id=5,body=doc5)

查询 1

res = es.search(index="english",body={"from":0,"size":5,
                                  "query":
                                      {"match_phrase":
                                          {"sentence":{"query":"Today is a sunny day"}
                                          }},

                                          "explain":False})

查询 2

 res = es.search(index="english",body={"from":0,"size":5,
                                  "query":{
                                    "bool":{
                                            "must":{
                                            "match_phrase":
                                          {"sentence":{"query":"Today is a sunny day"}
                                          }},
                                            "filter":{
                                                    "term":{
                                                            "sentence.word_count": 5}},

                                          }
                                            }
                                            })

因此,当我运行查询 1 时,我得到 doc2 作为最高结果,而我希望 doc1 成为最高结果。

当我尝试使用相同的过滤器(将搜索长度限制为查询长度)时,就像在查询 2 中一样,我没有得到任何结果。

如果我能得到任何帮助来解决这个问题,我将不胜感激。我想要给定查询的完全匹配,而不是包含该查询的匹配。

谢谢

【问题讨论】:

  • 如果您想要精确的词组匹配,为什么在查询 1 中将 slop 设置为 3?
  • 我的意思是,我希望匹配是用相同的词,顺序可以不同。
  • 那么这不是“完全匹配”,您应该更新您的问题以使其清楚;-)
  • 删除了 slop ;-)
  • 我的直觉告诉我,您的索引有 5 个主分片,并且您没有足够的文档来使分数相关。如果您使用单个主分片创建索引,您的第一个查询将返回您期望的文档。承诺 ;-)

标签: elasticsearch match-phrase


【解决方案1】:

我的直觉告诉我,您的索引有 5 个主分片,并且您没有足够的文档来使分数相关。如果您使用单个主分片创建索引,您的第一个查询将返回您期望的文档。您可以在以下文章中详细了解发生这种情况的原因:https://www.elastic.co/blog/practical-bm25-part-1-how-shards-affect-relevance-scoring-in-elasticsearch

实现您想要的结果的一种方法是使用keyword 类型但使用normalizer 来小写数据,以便以不区分大小写的方式更轻松地搜索完全匹配。

像这样创建索引:

PUT english
{
  "settings": {
    "analysis": {
      "normalizer": {
        "lc_normalizer": {
          "type": "custom",
          "filter": ["lowercase"]
        }
      }
    }
  },
  "mappings": {
    "sentences": {
      "properties": {
        "sentence": {
          "type": "text",
          "fields": {
            "exact": {
              "type": "keyword",
              "normalizer": "lc_normalizer"
            }
          }
        }
      }
    }
  }
}

然后你就可以像往常一样索引你的文档了。

PUT english/sentences/1
{"sentence": "Today is a sunny day"}
PUT english/sentences/2
{"sentence": "Today is a sunny day but tomorrow it might rain"}
...

终于可以搜索完全匹配的词组了,下面的查询只会返回doc1

POST english/_search
{
  "query": {
    "match": {
      "sentence.exact": "today is a sunny day"
    }
  }
}

【讨论】:

    【解决方案2】:

    尝试使用布尔查询

        PUT test_index/doc/1
        {"sentence": "Today is a sunny day"}
    
        PUT test_index/doc/2
        {"sentence": "Today is a sunny day but tomorrow it might rain"}
    
     -#terms query for exact match with keyword and multi match - phrase for other matches
        GET test_index/_search
        {
          "query": {
            "bool": {
              "should": [
                {
                  "terms": {
                    "sentence.keyword": [
                      "Today is a sunny day"
                    ]
                  }
                },
                {  
                  "multi_match":{  
                    "query":"Today is a sunny day",
                    "type":"phrase",
                    "fields":[  
                        "sentence"
                    ]
                  }
                }
              ]
            }
          }
        }
    

    另一个选项使用多重匹配,关键字匹配作为第一个,提升为 5,其他匹配没有提升:

    PUT test_index/doc/1
    {"sentence": "Today is a sunny day"}
    
    PUT test_index/doc/2
    {"sentence": "Today is a sunny day but tomorrow it might rain"}
    
    
    GET test_index/_search
    {  
      "query":{  
        "bool":{  
          "should":[  
            {  
              "multi_match":{  
                "query":"Today is a sunny day",
                "type":"phrase",
                "fields":[  
                  "sentence.keyword"
                ],
                "boost":5
              }
            },
            {  
              "multi_match":{  
                "query":"Today is a sunny day",
                "type":"phrase",
                "fields":[  
                    "sentence"
                ]
              }
            }
          ]
        }
      }
    }
    

    【讨论】:

      【解决方案3】:

      此查询将起作用 -

      {
          "query":{
              "match_phrase":{
                  "sentence":{
                      "query":"Today is a sunny day"
                  }
              }
          },
          "size":5,
          "from":0,
          "explain":false
      }
      

      【讨论】:

      • 感谢 Archit 的回答,但是如果我将 doc2 更改为“今天是晴天但明天可能会下雨”,它将无法正常工作。因此更新了doc2。我的错,我应该让我的问题更清楚。希望现在有意义。
      • 如果您想要精确匹配,您可以将其设为关键字而不是字符串。
      猜你喜欢
      • 1970-01-01
      • 2012-02-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-09
      • 1970-01-01
      • 2012-10-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多