Elasticsearch bool query_string 用于部分和全文匹配

med*_*ium 1 elasticsearch

我正在尝试创建一个 Elasticsearch 查询,该查询将对两个字段nametype我的索引执行部分和全文匹配,并返回包含特定uid字段值的所有匹配项。例如,我有以下记录:

  • { name: "Doug", "type": "Large"}
  • { name: "Doug Small", "type":"Large"}
  • { name: "Smal", "type": "Medium"}
  • { name: "Peter", "type": "Small"}

我希望我的查询能够匹配并返回所有这些记录。这是我到目前为止的查询:

{
  "query": {
    "bool": {
      "must": [
        {
          "query_string": {
            "fields": [
              "name",
              "type"
            ],
            "query": "*Doug Small*~",
            "default_operator": "AND"
          }
        }
      ],
      "filter": [
        {
          "match": {
            "uid": "123"
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

为了返回任何结果,我必须将查询包装起来,并在末尾*添加模糊。~对于该用例来说,这是正确的查询类型吗?

这是我的映射:

{
  "test": {
    "mappings": {
      "data": {
        "properties": {
          "uid": {
            "type": "keyword"
          },
          "name": {
            "type": "keyword"
          },
          "type": {
            "type": "keyword"
          }
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

Alk*_*ris 5

这里有多个问题需要考虑。

  1. 不要使用query_string,除非您确切知道自己在做什么。如果输入来自用户,请特别注意。更喜欢使用simple_query_string代替。
  2. 我怀疑您是否希望名称为 类型keyword。这种类型意味着不会分析该字符串(小写、标记化等)。因此,如果您使用完全相同的输入以外的内容进行搜索,那么它将不匹配。例如Doug Small。您可能会认为,既然您使用完全相同的输入进行搜索,至少会返回此文档,但事实并非如此。原因是query_stringorsimple_query_string输入被解析(并因此被标记化)。如果您不将输入指定为一项,那么它将不匹配。为此,您需要用双引号 (" \"Doug Small\" ") 将术语括起来。但如果你这样做,你就会输掉所有其他比赛。
  3. 我相信您需要的是 type 的名称和类型text。这意味着将分析保存的字符串(标记化、小写等,请检查简单分析器(如果您不指定其他分析器,则这是默认值)
  4. 您已指定运算符ANDfor query_string。这意味着所有查询词必须在名称或类型上匹配。但您声明您需要随查询返回所有文档。只有一份文档同时具有DougSmall。如果您需要这个,那么该运算符必须更改为OR(这是默认值)。

一个完整的例子

PUT test
{
  "mappings": {
    "properties": {
      "uid": {
        "type": "keyword"
      },
      "name": {
        "type": "text"
      },
      "type": {
        "type": "text"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)
POST test/_bulk
{ "index" : { "_id" : "1" } }
{ "name": "Doug", "type": "Large"}
{ "index" : { "_id" : "2" } }
{ "name": "Doug Small", "type":"Large"}
{ "index" : { "_id" : "3" } }
{ "name": "Smal", "type": "Medium"}
{ "index" : { "_id" : "4" } }
{ "name": "Peter", "type": "Small"}
Run Code Online (Sandbox Code Playgroud)
GET test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "simple_query_string": {
            "fields": [
              "name",
              "type"
            ],
            "query": "*Doug Small*",
            "default_operator": "OR"
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

上面的查询现在返回具有DougSmall/或两者的所有三个文档。此外,不区分大小写(因为现在已经对其进行了分析),因此这*doug small*将产生相同的 3 个结果。

由于现在对字段进行了分析,因此您不需要使用通配符,因为它现在用于第一个标记和最后一个标记。意义

  • *Doug Small*: 匹配任何有<ANYTHING>DogOR 的东西Small<Anything>
  • *Doug Smith Small*:匹配任何具有<ANYTHING>DogOR SmithOR 的Small<Anything>内容(OR -> 默认运算符,如果保留 AND,则它会相应更改)

所以我们也删除通配符

GET test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "simple_query_string": {
            "fields": [
              "name",
              "type"
            ],
            "query": "Doug Small",
            "default_operator": "OR"
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这会产生完全相同的 3 个结果。你还是失踪了Smal。现在您需要添加模糊匹配才能将其包含在内。

GET test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "simple_query_string": {
            "fields": [
              "name",
              "type"
            ],
            "query": "Doug Small~",
            "default_operator": "OR"
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

Doug Small~意味着将具有DougOR 的所有内容带到Small其中Small可能不完全匹配的内容。

您可以对所有术语进行模糊匹配

GET test/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "simple_query_string": {
            "fields": [
              "name",
              "type"
            ],
            "query": "Dg~ Small~",
            "default_operator": "OR"
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

之所以Dg匹配Doug是因为模糊程度https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#fuzziness

允许的最大编辑编辑距离(或编辑次数)