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

wqlqzqxt  于 2022-12-11  发布在  ElasticSearch
关注(0)|答案(3)|浏览(233)

我尝试在ElasticSearch中编写一个查询,它匹配单词中的连续字符。因此,如果我的索引有“John Doe”,我仍然应该看到Elasticsearch在下面的搜索中返回“John Doe”。
1.无名氏
1.约翰杜
1.翁岛
1.约翰

  1. n母鹿
    到目前为止,我已经尝试了以下查询。
{
  "query": {
    "multi_match": {
      "query": "term",
      "operator": "OR",
      "type": "phrase_prefix",
      "max_expansions": 50,
      "fields": [
        "Field1",
        "Field2"
      ]
    }
  }
}

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

woobm2wo

woobm2wo1#

正如我在上面的评论中所解释的,随着索引的增长,应该不惜一切代价避免使用前缀通配符,因为这将迫使ES进行全索引扫描。我仍然相信ngram(更准确地说是edge-ngram)是可行的方法,所以我在下面尝试一下。
其思想是索引输入的所有后缀,然后使用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"
    }
  }
}
46qrfjad

46qrfjad2#

这对我来说是有效的。代替一个ngram,索引你的数据作为关键字。并使用通配符正则表达式匹配来匹配单词。

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

zd287kbt3#

以下是更新的修复程序
link to the code
more options with tokenizers
创建索引

body = {
  "settings": {
    "analysis": {
      "analyzer": {
        "autocomplete": {
          "tokenizer": "autocomplete",
          "filter": [
            "lowercase"
          ]
        },
        "autocomplete_search": {
          "tokenizer": "lowercase"
        }
      },
      "tokenizer": {
        "autocomplete": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 10,
          "token_chars": [
            "letter"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "autocomplete",
        "search_analyzer": "autocomplete_search"
      }
    }
  }
}

相关问题