通配符查询Elasticsearch不适用于多字值

im9ewurl  于 2023-10-17  发布在  ElasticSearch
关注(0)|答案(1)|浏览(133)

我在wildcard query search中遇到了一些问题。
我的目的是,如果我搜索word1 word2 word3,我会找到所有的结果,可以有前缀和后缀之前和之后的每个词组成整个字符串
我的索引结构是:

{
  "my_index": {
    "aliases": {},
    "mappings": {
      "properties": {
        "attributes": {
          "properties": {
            "name": {
              "properties": {
                "value": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                }
              }
            },
          }
        }
      }
    },
    "settings": {
      ...
    }
  }
}

所以我有一个字段attributes.name(文本),我想匹配值。
我的索引包含attributes.name值的对象:

  • word1
  • word1suffix
  • word1 word2
  • word1 word2suffix
  • word1 word2 word3

在运行搜索之前,我在内部在每个单词之前和之后添加通配符
word1 word2 word3 => *word1* *word2* *word3*
然后我运行这个查询:

{
  "size": 10,
  "index": "my_index",
  "body": {
    "query": {
      "bool": {
        "should": [
          {
            "wildcard": {
              "attributes.name.value": {
                "value": "*word1* *word2* *word3*",
                "rewrite": "constant_score"
              }
            }
          }
        ],
        "must": [],
        "minimum_should_match": 1
      }
    }
  },
  "explain": false
}

我面临的奇怪的事情是,即使在索引中我有一个名为word1 word2 word3的对象,我也无法通过这种搜索找到它(我知道在这种情况下,最好是一个 match_phraseterm 查询,但这只是为了理解为什么这个简单的情况不起作用)。
如果我试着用更少的词,比如:

  • *word1*,我找到了word1word1suffixword1 word2word1 word2suffix
  • *word1* *word2*,我发现word1 word2word1 word2suffix
  • *word1* *word2* *word3*
    因此,这种奇怪的行为似乎始于我搜索包含太多单词的结果。

只是为了调试,我的值以这种方式存储在索引中:

{
    "attributes": {
        "name": [{
            "value": "word1 word2 word3"
        }],
    }
}

**最后一个考虑:**我设法找到word1 word2 word3通过搜索字段attributes.name.value.keyword(我认为.keyword是自动生成的索引中的每一个文本字段),而不是attributes.name.value。问题是,如果我使用.keyword,分析器不工作,所以我认为这不是一个好的解决方案。

h79rfbju

h79rfbju1#

重复查询基于模式工作,因此它会将整个查询视为一个模式,因此当您添加多个单词时可能会不匹配。
你有两个选择:
首先是使用query_string类型的查询,如下图所示,您可以根据需求将default_operator的值设置为ANDOR。这将仅在内部创建bool查询:

{
 "query": {
   "bool": {
     "should": [
       {
        "query_string": {
          "default_field": "value",
          "query": "*word1* *word2* *word3*",
          "default_operator": "AND"
        }
       }
     ]
   }
 }
}

其次,您可以在must中为AND查询和在should中为OR查询条件设置多个wildcard查询:

{
  "query": {
    "bool": {
      "must": [
        {
          "wildcard": {
            "value": {
              "value": "*word1*"
            }
          }
        },
        {
          "wildcard": {
            "value": {
              "value": "*word2*"
            }
          }
        },
        {
          "wildcard": {
            "value": {
              "value": "*word3*"
            }
          }
        }
      ]
    }
  }
}

更新

我通过搜索字段attributes.name.value.keyword(我认为.keyword是在每个文本字段的索引中自动生成的)而不是attributes.name.value找到了word1 word2 word3。问题是,如果我使用.keyword,分析器不工作,所以我认为这不是一个好的解决方案。
是的,如果你没有配置mapping,那么弹性将自动为每个字段创建Map,如果字段被发现为text类型,那么它也会创建一个keyword类型的内部字段。
它正在工作,因为keyword字段不应用任何分析器,它会查找精确匹配。如果您尝试wildcard查询attributes.name.value.keyword字段与多个术语,那么它将工作,但它是区分大小写的。所以如果你有像word1 word2 word3这样的字段值,那么*word1* *word2* *word3*这个查询会工作,但是*Word1* *word2* *word3*这个查询不会工作。(W是大写的)。

为什么text类型字段不工作?

因为wildcard查询是术语级查询,并且在查询时不应用任何analyzer。它会将你的整个查询视为一个模式。您正在匹配text类型字段上的查询,该字段在索引时使用standard分析器,并将文本标记为多个术语和索引,因此它适用于一个术语而不是多个术语。

性能影响

不建议使用以*?开头的URL,因为它会影响搜索性能。下面是一个文件中提到的警告:
避免以 * 或?这会增加查找匹配项所需的迭代次数,并降低搜索性能。

相关问题