【问题标题】:Elastic search partial match but strict phrase matching弹性搜索部分匹配但严格的短语匹配
【发布时间】:2021-04-22 13:15:22
【问题描述】:

我正在寻找一种方法来模糊部分匹配单词匹配的字段,但是我还想添加严格的短语匹配。

即说我有诸如

之类的字段
foo bar
bar foo

我想实现以下搜索行为:

  • 如果我搜索foo,我想返回两个结果。

  • 如果我搜索ba,我想返回两个结果。

  • 如果我搜索bar foo,我只想返回一个结果。

  • 如果我搜索bar foo foo,我不想返回任何结果。

我还想添加单字符模糊匹配,所以如果foo 被错误输入为fbo,那么它会返回两个结果。

我当前的搜索和索引分析器使用edge_gram 标记器并且工作得相当好,除非有任何 gram 匹配,否则无论以下单词是否匹配,它都会返回结果。即我的搜索将返回以下搜索结果bar foo buzz

foo bar
bar foo

我的 tokenzier:

ngram_tokenizer: {
   type: "edge_ngram",
   min_gram: "2",
   max_gram: "15",
   token_chars: ['letter', 'digit', 'punctuation', 'symbol'],
},
          

我的分析仪:

nGram_analyzer: {
  filter: [
  lowercase,
    "asciifolding"
  ],
  type: "custom",
  tokenizer: "ngram_tokenizer"
},

我的字段映射:


type: "search_as_you_type",
doc_values: false,
max_shingle_size: 3,
analyzer: "nGram_analyzer"
          

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    满足您所有要求的一种方法是使用span_near查询

    span near query要长得多,但这些适合与模糊参数一起进行短语匹配

    添加一个包含索引数据、搜索查询和搜索结果的工作示例

    索引映射:

    {
      "mappings": {
        "properties": {
          "title": {
            "type": "text"
          }
        }
      }
    }
    

    索引数据:

    {
        "title":"bar foo"
    }
    {
        "title":"foo bar"
    }
    

    搜索查询:

    如果我搜索foo,我想返回两个结果。

    {
      "query": {
        "bool": {
          "must": [
            {
              "span_near": {
                "clauses": [
                  {
                    "span_multi": {
                      "match": {
                        "fuzzy": {
                          "title": {
                            "value": "foo",
                            "fuzziness": 2
                          }
                        }
                      }
                    }
                  }
                ],
                "slop": 0,
                "in_order": true
              }
            }
          ]
        }
      }
    }
    

    搜索结果:

    "hits": [
          {
            "_index": "67205552",
            "_type": "_doc",
            "_id": "2",
            "_score": 0.18232156,
            "_source": {
              "title": "bar foo"
            }
          },
          {
            "_index": "67205552",
            "_type": "_doc",
            "_id": "1",
            "_score": 0.18232156,
            "_source": {
              "title": "foo bar"
            }
          }
        ]
    

    如果我搜索ba,我想返回两个结果。

    {
      "query": {
        "bool": {
          "must": [
            {
              "span_near": {
                "clauses": [
                  {
                    "span_multi": {
                      "match": {
                        "fuzzy": {
                          "title": {
                            "value": "ba",
                            "fuzziness": 2
                          }
                        }
                      }
                    }
                  }
                ],
                "slop": 0,
                "in_order": true
              }
            }
          ]
        }
      }
    }
    

    搜索结果:

    "hits": [
          {
            "_index": "67205552",
            "_type": "_doc",
            "_id": "2",
            "_score": 0.18232156,
            "_source": {
              "title": "bar foo"
            }
          },
          {
            "_index": "67205552",
            "_type": "_doc",
            "_id": "1",
            "_score": 0.18232156,
            "_source": {
              "title": "foo bar"
            }
          }
        ]
    

    如果我搜索bar foo foo,我不想返回任何结果。

    {
      "query": {
        "bool": {
          "must": [
            {
              "span_near": {
                "clauses": [
                  {
                    "span_multi": {
                      "match": {
                        "fuzzy": {
                          "title": {
                            "value": "bar",
                            "fuzziness": 2
                          }
                        }
                      }
                    }
                  },
                  {
                    "span_multi": {
                      "match": {
                        "fuzzy": {
                          "title": {
                            "value": "foo",
                            "fuzziness": 2
                          }
                        }
                      }
                    }
                  },
                  {
                    "span_multi": {
                      "match": {
                        "fuzzy": {
                          "title": {
                            "value": "foo",
                            "fuzziness": 2
                          }
                        }
                      }
                    }
                  }
                ],
                "slop": 0,
                "in_order": true
              }
            }
          ]
        }
      }
    }
    

    搜索结果将为空

    【讨论】:

    • 您好 ESCoder,感谢您的深入审查。是否可以在不必将每个单词拆分为自己的“span_multi”匹配查询的情况下达到预期的结果?即bar foo foo 将是单个查询而不是复合 span_multi 查询?
    • @ErrolGreen 据我所知,除了使用 span 查询,我认为没有其他方法可以实现模糊匹配的短语
    • 如果我放弃模糊性要求,会有一个只需要一个子句的解决方案吗?
    • @ErrolGreen 不,仍然不会有任何其他方式,因为您还需要严格的短语匹配。
    • @ErrolGreen 确实,跨度查询有点冗长,但根据您的要求,只有这个才适用。我尝试了所有其他可能的方法,但想不出任何其他方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-30
    • 2020-11-09
    相关资源
    最近更新 更多