Я получил ответ от форумаasticsearch:
Вы используете фильтр токенов edge_ngram.Давайте посмотрим, как ваш анализатор обрабатывает строку запроса "ho"
.Предполагая, что ваш индекс называется my_index
:
GET my_index/_analyze
{
"text": "ho",
"analyzer": "autocomplete"
}
Ответ показывает, что на выходе вашего анализатора будет два токена в позиции 0:
{
"tokens": [
{
"token": "h",
"start_offset": 0,
"end_offset": 2,
"type": "word",
"position": 0
},
{
"token": "ho",
"start_offset": 0,
"end_offset": 2,
"type": "word",
"position": 0
}
]
}
Что делает Elasticsearchзапрос для двух токенов в одной позиции?Он обрабатывает запрос как «ИЛИ», даже если вы используете тип "phrase"
.Вы можете видеть это из выходных данных API проверки (который показывает запрос Lucene, в который был записан ваш запрос):
GET my_index/_validate/query?rewrite=true
{
"query": {
"match": {
"name": {
"query": "ho",
"type": "phrase"
}
}
}
}
Поскольку и ваш запрос, и ваш документ имеют h
в позиции 0, документ станет хитом.
Теперь, как это решить?Вместо токен-фильтра edge_ngram вы можете использовать токенайзер edge_ngram .Этот токенизатор увеличивает позицию каждого выводимого им токена.
Итак, если вы вместо этого создадите свой индекс следующим образом:
PUT my_index
{
"settings": {
"number_of_shards": 1,
"analysis": {
"tokenizer": {
"autocomplete_tokenizer": {
"type": "edge_ngram",
"min_gram": 1,
"max_gram": 20
}
},
"analyzer": {
"autocomplete": {
"type": "custom",
"tokenizer": "autocomplete_tokenizer",
"filter": [
"lowercase"
]
}
}
}
},
"mappings": {
"doc": {
"properties": {
"name": {
"type": "string",
"analyzer": "autocomplete"
}
}
}
}
}
Вы увидите, что этот запрос больше не является хитом:
GET my_index/_search
{
"query": {
"match": {
"name": {
"query": "ho",
"type": "phrase"
}
}
}
}
Но вот, например, это:
GET my_index/_search
{
"query": {
"match": {
"name": {
"query": "he",
"type": "phrase"
}
}
}
}