在ElasticSearch中查询以匹配单词的一部分

use*_*107 4 elasticsearch

我试图在ElasticSearch中编写一个查询,该查询匹配单词中的连续字符。因此,如果我的索引包含“ John Doe”,则对于以下搜索,我仍然应该看到Elasticsearch返回的“ John Doe”。

  1. 约翰·杜
  2. 约翰·杜
  3. 哦做
  4. 约翰
  5. 母鹿

到目前为止,我已经尝试了以下查询。

{
  "query": {
    "multi_match": {
      "query": "term",
      "operator": "OR",
      "type": "phrase_prefix",
      "max_expansions": 50,
      "fields": [
        "Field1",
        "Field2"
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但这也会返回不必要的匹配,例如当我键入john x时我仍然会得到“ John Doe”。

Val*_*Val 7

正如我在上面的评论中所解释的那样,随着索引的增长,应该不惜一切代价避免使用前缀通配符,因为这将迫使ES进行完整的索引扫描。我仍然坚信ngrams(更确切地说是edge-ngrams)是要走的路,因此我在下面对此进行了介绍。

这个想法是索引输入的所有后缀,然后使用prefix查询来匹配任何后缀,因为搜索前缀不会遇到与搜索后缀相同的性能问题。因此,想法是索引john doe如下:

john doe
ohn doe
hn doe
n doe
doe
oe
e
Run Code Online (Sandbox Code Playgroud)

这样,使用prefix查询,我们可以匹配这些标记的任何子部分,从而有效地实现匹配部分连续单词的目标,同时确保良好的性能。

索引的定义如下:

PUT my_index
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "my_analyzer": {
            "type": "custom",
            "tokenizer": "keyword",
            "filter": [
              "lowercase",
              "reverse",
              "suffixes",
              "reverse"
            ]
          }
        },
        "filter": {
          "suffixes": {
            "type": "edgeNGram",
            "min_gram": 1,
            "max_gram": 20
          }
        }
      }
    }
  },
  "mappings": {
    "doc": {
      "properties": {
        "name": {
          "type": "text",
          "analyzer": "my_analyzer",
          "search_analyzer": "standard"
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以为样本文档建立索引:

PUT my_index/doc/1
{
  "name": "john doe"
}
Run Code Online (Sandbox Code Playgroud)

最后,以下所有搜索将返回john doe文档:

POST my_index/_search 
{
  "query": {
    "prefix": {
      "name": "john doe"
    }
  }
}

POST my_index/_search 
{
  "query": {
    "prefix": {
      "name": "john do"
    }
  }
}

POST my_index/_search 
{
  "query": {
    "prefix": {
      "name": "ohn do"
    }
  }
}

POST my_index/_search 
{
  "query": {
    "prefix": {
      "name": "john"
    }
  }
}

POST my_index/_search 
{
  "query": {
    "prefix": {
      "name": "n doe"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


use*_*107 2

这对我有用。将数据作为关键字索引,而不是 ngram。并使用通配符正则表达式匹配来匹配单词。

 "query": {
          "bool": {
              "should": [
                {
                  "wildcard": { "Field1": "*" + term + "*" }
                },
                {
                  "wildcard": { "Field2": "*" + term + "*" }
                }
              ],
              "minimum_should_match": 1
          }
      }
Run Code Online (Sandbox Code Playgroud)