具有 multi_match 和 bool_prefix 类型的 Elasticsearch 模糊性

分享于2022年07月17日 elasticsearch fuzzy-search 问答
【问题标题】:具有 multi_match 和 bool_prefix 类型的 Elasticsearch 模糊性(Elasticsearch fuzziness with multi_match and bool_prefix type)
【发布时间】:2022-01-08 05:01:48
【问题描述】:

我有一组 search_as_you_type_fields 我需要搜索。这是我的地图

"mappings" : {
      "properties" : {
        "description" : {
          "type" : "search_as_you_type",
          "doc_values" : false,
          "max_shingle_size" : 3
        },
        "questions" : {
          "properties" : {
            "content" : {
              "type" : "search_as_you_type",
              "doc_values" : false,
              "max_shingle_size" : 3
            },
            "tags" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword"
                }
              }
            }
          }
        },
      
        "title" : {
          "type" : "search_as_you_type",
          "doc_values" : false,
          "max_shingle_size" : 3
        },
      }
    }

我正在使用 bool_prefix 类型的 multi_match 查询。

"query": {
    "multi_match": {
      "query": "triangle", 
      "type": "bool_prefix",
       "fields": [
           "title",
           "title._2gram",
           "title._3gram",
           "description",
           "description._2gram",
           "description._3gram",
           "questions.content",
           "questions.content._2gram",
           "questions.content._3gram",
           "questions.tags",
           "questions.tags._2gram",
           "questions.tags._3gram"
       ]
    }
  }

到目前为止工作正常。现在我想添加一个错字容错,这是 ES 中的模糊性。但是,看起来 bool_prefix 与此有一些冲突。因此,如果我修改查询并添加“fuzziness”:“AUTO”并在单词“triangle”->“triangld”中出错,它将不会得到任何结果。

但是,如果我正在寻找一个短语“直角三角形”,我有一些不同的行为:

  1. 即使没有拼写错误,我也能通过“模糊”获得更多结果:“AUTO”(1759 与 1267)
  2. 如果我在 2d 单词“right triangdd”中添加错字,它似乎可以工作,但看起来它现在会首先推送包含“right”而没有“triangle”的结果(“权利法案”、“正当程序和隐私权”等)。
  3. 如果我在第一个单词(“直角三角形”)或两者(“右三角”)中打错字,结果似乎还不错。所以这可能是唯一正确的行为。

我看过几篇文章,甚至 GitHub 上的问题,即模糊性在使用 bool_prefix 的 multi_match 查询时无法正常工作,但我找不到解决方法。我尝试更改查询类型,但看起来 bool_prefix 是唯一支持在您键入时进行搜索的类型,并且我需要在用户开始输入内容时获取搜索结果。

由于我从后端发出来自 ES 的所有请求,因此我还可以操作查询字符串以在需要时构建不同的搜索查询类型。例如,对于 1 个单词搜索,使用一种类型进行多使用另一种。但我基本上需要保持当前的行为。

我还尝试在字符串中附加一个符号“~”或“~1[2]”,这似乎是指定模糊性的另一种方式,但结果相当不清楚,性能(搜索速度)似乎变得更糟。

我的问题是:

  1. 如何实现 1 字搜索的模糊性?以便查询“triangld”返回包含“triangle”等的文档。
  2. 当查询的 2d(最后一个?)单词中出现拼写错误时,如何获得正确的搜索结果?就像我上面提到的那样,它有效,但请参阅上面的第 2 点
  3. 即使短语正确,为什么只添加模糊性(参见第 1 页)会返回更多结果?
  4. 我的分析仪等有什么需要改变的吗?


【解决方案1】:

为了达到预期的行为,我们做了以下工作:

  1. 将查询类型更改为“query_string”
  2. 在后端添加了查询字符串预处理。我们用空格分割查询字符串,如果每个单词的长度分别超过 4 个字符或 8 个字符,则在每个单词中添加“~1”或“~2”。 ~ 是 ES 中的一种模糊语法。但是,在用户键入空格之前,我们不会将其添加到当前键入的单词中。例如,用户输入 [t, tr, tri, ... triangle] => 没有模糊,但一次“triangle” => “triangle~2”。这是因为最后一个词有模糊性会有意想不到的结果
  3. 我们还从搜索字段中删除了所有 ngram 字段,因为我们得到了相同的结果,但性能要好一些。
  4. 在查询中添加了“default_operator”:“AND”以包含短语查询的一个字段的结果