我想在ElasticSearch中编写查询,该查询提供的结果包含搜索查询中的所有单词,但不仅包含完整单词,还包含子单词。例如,如果我的文档具有以下值:
{
"first_name":"didier",
"last_name":"drogba"
}
并且我搜索“ didi dro”,应该返回此文档。如果我搜索“ david drogba”,则文档应被忽略,因为它不包含单词“ david”,甚至不包含子单词。 我使用ngram tokenizer进行了尝试,但无法实现我想要的功能。
我创建的索引
PUT doctors
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "my_tokenizer"
}
},
"tokenizer": {
"my_tokenizer": {
"type": "ngram"
}
}
}
}
}
然后添加映射
put doctors/_doc/_mapping
{
"properties": {
"first_name": {
"type": "text",
"analyzer": "my_analyzer"
},
"last_name": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
添加一些文档
post doctors/_doc/1
{
"first_name": "dito",
"last_name": "janelidze",
"specialism": "oftalmologist",
"location_name":"evex saburtalo clinic",
"brand": "Evex",
"address":"kavtaradze street N21"
}
我的搜索查询如下
get doctors/_doc/_search
{
"query": {
"multi_match": {
"query": "david jane",
"fields": ["first_name", "last_name"]
}
}
}
它给了我插入的文档,但我不需要它,因为它不包含单词“ david”
答案 0 :(得分:1)
+1表示每个单词的“ and”运算符。使用此功能,对我有用(也可以用于自动完成功能)。
settings:
analysis": {
"filter": {
"name_ngrams": {
"max_gram": "20",
"type": "edgeNGram",
"min_gram": "1",
"side": "front"
}
},
"analyzer": {
"partial_name": {
"type": "custom",
"filter": [
"lowercase",
"name_ngrams",
"standard",
"asciifolding"
],
"tokenizer": "standard"
},
"full_name": {
"type": "custom",
"filter": [
"standard",
"lowercase",
"asciifolding"
],
"tokenizer": "standard"
}
}
mapping:
"first_name": {
"type": "text",
"index_analyzer": "partial_name",
"search_analyzer": "full_name"
},
"last_name": {
"type": "text",
"index_analyzer": "partial_name",
"search_analyzer": "full_name"
},
答案 1 :(得分:1)
N-Gram tokenizer将根据输入单词构造指定 length 个单词。 长度 在映射中被指定为min_gram
和max_gram
,如果您未指定,则默认为1
,分别2
。
我已经分别更新了min_gram:3
和max_gram:5
所提供的映射。
然后N-Gram Tokenizer将创建令牌,例如对于didier
,它们将是did, idi, die, ier, didi, idie, dier, didie, idier
,最终将它们存储在反向索引中。
将默认1和2分别设置为min_gram
和max_gram
,请注意didier
和david
将id
作为公共子词,这就是为什么它们返回。
映射
PUT doctors
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "my_tokenizer"
}
},
"tokenizer": {
"my_tokenizer": {
"type": "ngram",
"min_gram": 3,
"max_gram": 6,
}
}
}
}
}
也就是说,尽管更改了映射,但是如果您的查询字符串使用的是david jane
,它将在david or jane
或first_name
中搜索last_name
。这意味着文档dito janelidze
仍将返回(但得分比具有david jane
的得分更低)
使用运算符AND
将在david AND jane
或first_name
中以last_name
进行搜索,这不是您想要的。
相反,您可以使用以下布尔查询或创建另一个名为name
的字段,将first_name
和last_name
的值复制到其中使用copy_to字段,然后使用该字段进行搜索。
查询
POST <your_index_name>/_search
{
"query": {
"bool":{
"must": [
{
"match": {
"first_name": "david"
}
},
{
"match": {
"last_name": "jane"
}
}
]
}
}
}
不幸的是,由于所需的更改在映射级别,因此您将需要删除,重新创建索引并再次摄取文档。
希望这会有所帮助!