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

时间:2018-05-22 23:59:48

标签: elasticsearch

我正在尝试在ElasticSearch中编写一个查询,该查询匹配单词中的连续字符。所以,如果我的索引有" John Doe",我仍然应该看到" John Doe" Elasticsearch为以下搜索返回。

  1. john doe
  2. john do
  3. ohn do
  4. 约翰
  5. n doe
  6. 到目前为止,我已尝试过以下查询。

    {
      "query": {
        "multi_match": {
          "query": "term",
          "operator": "OR",
          "type": "phrase_prefix",
          "max_expansions": 50,
          "fields": [
            "Field1",
            "Field2"
          ]
        }
      }
    }
    

    但是,这也会让我回归,这样我仍然可以得到#22; John Doe"当我输入john x。

2 个答案:

答案 0 :(得分:3)

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

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

john doe
ohn doe
hn doe
n doe
doe
oe
e

这样,使用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"
        }
      }
    }
  }
}

然后我们可以索引一个示例文档:

PUT my_index/doc/1
{
  "name": "john doe"
}

最后,以下所有搜索都将返回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"
    }
  }
}

答案 1 :(得分:2)

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

 "query": {
          "bool": {
              "should": [
                {
                  "wildcard": { "Field1": "*" + term + "*" }
                },
                {
                  "wildcard": { "Field2": "*" + term + "*" }
                }
              ],
              "minimum_should_match": 1
          }
      }