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

Другие вопросы по тегам