Elasticsearch с индексацией ngram не находит частичных совпадений
Итак, у меня есть индекс asticsearch, который был создан следующим образом:
curl -XPUT 'http://localhost:9200/person' -d '{
"settings": {
"number_of_shards": 1,
"analysis": {
"filter": {
"autocomplete_filter": {
"type": "edge_ngram",
"min_gram": 1,
"max_gram": 20
}
},
"analyzer": {
"autocomplete": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"autocomplete_filter"
]
}
}
}
}
}'
Опросив человека по имени 'ian', я получаю два результата
curl -XGET http://localhost:9200/person/_search -d '{
"query": {
"match": {
"_all": "ian"
}
}
}’
Но при запросе только буквы ia
Я должен получить столько же или больше результатов, но вместо этого я не получаю:
curl -XGET http://localhost:9200/person/_search -d '{
"query": {
"match": {
"_all": "ia"
}
}
}’
Что-то не так в моем edge_ngram
настройка фильтра? Как я могу решить это?
РЕДАКТИРОВАТЬ: чтобы уточнить, я хотел бы, чтобы мое заявление вставки смотреть в соответствии с этим
curl -XPOST "http://localhost:9200/person/RANDOM_STRING HERE/ANOTHER_RANDOM_STRING" -d "{
"field1" : "value",
"field2" : "value",
"field3" : "value"
}"
После вставки я бы хотел, чтобы все поля были проанализированы с помощью edge_ngram, чтобы я мог выполнять поиск по частичным строкам по любому из этих полей и получать этот результат.
3 ответа
Если вы просто хотите использовать свой анализатор для каждого типа и всех свойств (если не указано иное), вам просто нужно установить анализатор "по умолчанию" для индекса. У меня проблемы с поиском этого в документах ES (они не всегда очень удобны для пользователя), но вот пример. Я использую ES 1.5, хотя я не думаю, что это имеет значение.
PUT /person
{
"settings": {
"number_of_shards": 1,
"analysis": {
"filter": {
"autocomplete_filter": {
"type": "edge_ngram",
"min_gram": 1,
"max_gram": 20
}
},
"analyzer": {
"default": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"autocomplete_filter"
]
}
}
}
}
}
Затем я проиндексировал документы и выполнил ваш запрос, и он работал нормально:
POST /person/doc/_bulk
{"index":{"_id":1}}
{"name":"Ian"}
{"index":{"_id":2}}
{"name":"Bob Smith"}
POST /person/_search
{
"query": {
"match": {
"_all": "ia"
}
}
}
...
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1.4142135,
"hits": [
{
"_index": "person",
"_type": "doc",
"_id": "1",
"_score": 1.4142135,
"_source": {
"name": "Ian"
}
}
]
}
}
Вот код:
http://sense.qbox.io/gist/4e2114aafc4f3c507b4f23da8bb83f3ab00e2288
Поле _all будет использовать анализатор по умолчанию "standard", если вы не укажете один для него. Таким образом, токены в поле _all не являются edge_ngram. Следовательно, нет никакого результата при поиске "ia". Как правило, вы хотите избегать использования поля _all для поиска частичных совпадений, поскольку это может привести к неожиданным или запутанным результатам.
Если вам все еще нужно использовать поле _all, тогда определите анализатор как "автозаполнение" для него.
Вы не указали какие-либо типы, которые используют ваш анализатор. Итак, вы определили анализатор, но не использовали его. Когда вы сохраняете документы в новом типе, отображение будет определено неявно, и будет использоваться стандартный анализатор, который не создает термины с частичными словами, поэтому ваш поиск по запросу "ia" ничего не соответствует.
Одним из способов справиться с этим является явное определение вашего типа и указание анализаторов, которые вы хотите использовать в отображении. Вот пример, где имя индекса - это "человек" (как и у вас), а имя типа - "doc" со свойством "имя", которое использует ваш анализатор для индексации (но не для поиска):
PUT /person
{
"settings": {
"number_of_shards": 1,
"analysis": {
"filter": {
"autocomplete_filter": {
"type": "edge_ngram",
"min_gram": 1,
"max_gram": 20
}
},
"analyzer": {
"autocomplete": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"autocomplete_filter"
]
}
}
}
},
"mappings": {
"doc":{
"properties": {
"name": {
"type": "string",
"index_analyzer": "autocomplete",
"search_analyzer": "standard"
}
}
}
}
}
Чтобы проверить это, я добавил пару документов:
POST /person/doc/_bulk
{"index":{"_id":1}}
{"name":"Ian"}
{"index":{"_id":2}}
{"name":"Bob Smith"}
Затем запустил запрос на сопоставление с "name"
поле:
POST /person/_search
{
"query": {
"match": {
"name": "ia"
}
}
}
...
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "person",
"_type": "doc",
"_id": "1",
"_score": 1,
"_source": {
"name": "Ian"
}
}
]
}
}
Вот код, который я использовал для тестирования нескольких вещей, в том числе с помощью "_all"
поле таким образом, чтобы ваш исходный запрос работал:
http://sense.qbox.io/gist/61df5d17343651884c9422198b6a6bc00a6acb04