ElasticSearch search_analyzer применен, но результат не возвращен

У меня есть запрос, который должен искать слова в нижнем регистре.

На самом деле у меня был index_analyzer с фильтром нижнего регистра, но я хотел добавить также search_analyzer, чтобы выполнять поиск без учета регистра.

"analysis": {
    "analyzer" : {
        "DefaultAnalyzer": {
            "type": "custom",
            "tokenizer": "whitespace",
            "filter": [
                "lowercase"
            ],
            "char_filter": ["punctuation"]
        },
        "MyAnalyzer": {
            "type": "custom",
            "tokenizer": "first_letter",
            "filter": [
                "lowercase"
            ]
        },

Так что я просто подумал добавить тот же анализатор, что и search_analyzer в сопоставление

"index_analyzer": "DefaultAnalyzer",
"search_analyzer": "DefaultAnalyzer",
"dynamic" : false,
"_source": { "enabled": true },
"properties" : {
    "name": {
        "type": "multi_field",
        "fields": {
            "name": {
                "type": "string",
                "store": true
            },
            "startletter": {
                "type": "string",
                "index_analyzer": "MyAnalyzer",
                "search_analyzer": "MyAnalyzer",
                "store": true
            }
        }
    },

Делая это, если я вручную запрашиваю Elastic Search с помощью

curl -XGET host:9200/my-index/_analyze -d 'Test'

Я вижу, что термин запроса правильно написан в нижнем регистре

{
  "tokens": [
    {
      "token": "test",
      "start_offset": 0,
      "end_offset": 4,
      "type": "<ALPHANUM>",
      "position": 1
    }
  ]
}

Но выполнение из кода

  • если я использую поисковый термин в верхнем регистре, ES возвращает ноль совпадений (даже если мы видели, что применяется search_analyzer)
  • если я использую поисковый запрос в нижнем регистре, ES возвращает мне правильное количество результатов (сотни)

Хотя я хотел бы иметь такой же результат независимо от случая.

В коде я просто создаю запрос с фильтром терминов, вот так

{
  "filter": {
    "term": {
      "name.startletter": "O"
    }
  },
  "size": 10000,
  "query": {
    "match_all": {}
  }
}

Что я делаю неправильно? Почему я не получаю никакого результата?


person Kamafeather    schedule 06.08.2014    source источник
comment
Я не понимаю причину понижения голоса. Глупый вопрос или я что-то не так сделал?...   -  person Kamafeather    schedule 08.08.2014


Ответы (2)


Проблема в том, что вы используете фильтр терминов. Фильтр терминов не анализирует используемый текст:

Фильтр терминов

Фильтрует документы, поля которых содержат термин (не анализируется). Аналогичен терм-запросу, за исключением того, что действует как фильтр.

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-term-filter.html

Поскольку он не анализирует, он не использует определенный вами анализатор.

Как правило, вы хотите использовать фильтры терминов и запросы с полями, которые не анализируются. Измените тип фильтра на что-то, что будет анализировать во время запроса.

person John Petrone    schedule 06.08.2014
comment
Ты прав! Какой фильтр я мог бы использовать в качестве альтернативы, чтобы сделать то же самое? (поиск по начальной букве в нижнем регистре) Я пытаюсь использовать фильтр Bool, но в итоге все равно добавляю в него фильтр Term. Фильтр Match_all? Еще один? - person Kamafeather; 07.08.2014
comment
Я фактически переключился на фильтр запроса, используя тот же {term: {name.startletter: O}} в запросе, а не непосредственно в фильтре. На ваш взгляд, это хорошее решение? Не потеряю ли я производительность при использовании запроса (даже если внутри фильтра)? - person Kamafeather; 08.08.2014
comment
Я, наконец, остановился на этом решении с Query Filter. Спасибо. - person Kamafeather; 19.08.2014

Я думаю, вы используете MyAnalyzer для получения начальной буквы индексации, ваш анализатор так не работает. Я сделал несколько тестов и, наконец, нашел решение.

Сначала создайте индекс и сопоставление (+ настройки)

curl -XPUT "http://localhost:9200/t1" -d'
{
   "settings": {
      "index": {
         "analysis": {
            "analyzer": {
               "DefaultAnalyzer": {
                  "type": "custom",
                  "tokenizer": "whitespace",
                  "filter": [
                     "lowercase"
                  ]
               },
               "MyAnalyzer": {
                  "type": "custom",
                  "tokenizer": "token_letter",
                  "filter": [
                     "one_token","lowercase"
                  ]
               }
            },
            "tokenizer": {
               "token_letter": {
                  "type": "edgeNGram",
                  "min_gram": "1",
                  "max_gram": "1",
                  "token_chars": [
                     "letter",
                     "digit"
                  ]
               }
            },
            "filter": {
               "one_token": {
                  "type": "limit",
                  "max_token_count": 1
               }
            }
         }
      }
   },
   "mappings": {
      "t2": {
         "index_analyzer": "DefaultAnalyzer",
         "search_analyzer": "DefaultAnalyzer",
         "dynamic": false,
         "_source": {
            "enabled": true
         },
         "properties": {
            "name": {
               "type": "multi_field",
               "fields": {
                  "name": {
                     "type": "string",
                     "store": true
                  },
                  "startletter": {
                     "type": "string",
                     "index_analyzer": "MyAnalyzer",
                     "search_analyzer": "simple",
                     "store": true
                  }
               }
            }
         }
      }
   }
}'

А теперь напишите данные.

curl -XPUT "http://localhost:9200/t1/t2/1" -d'
{
    "name" :"Oliver Khan"
}'

Теперь, вот забавная часть, просто запрос и аспект, чтобы увидеть, что проиндексировано.

curl -XPOST "http://localhost:9200/t1/t2/_search" -d'
{
  "filter": {
    "term": {
      "name.startletter": "O"
    }
  },
  "size": 10000,
  "query": {
    "match_all": {}
  },
  "facets": {
     "tf": {
        "terms": {
           "field": "name.startletter",
           "size": 10
        }
     }
  }
}'

Это дает мне проанализированный текст в виде фасетного вывода, поэтому я могу проверить, работает ли анализатор. Надеюсь это поможет!!

person progrrammer    schedule 06.08.2014
comment
Спасибо за ваши усилия! Кстати, я хотел бы сохранить тот же анализатор, что и search_analyzer (если в будущем анализаторы будут меняться, я хочу, чтобы изменения отражались и в индексации, и в поиске). - person Kamafeather; 08.08.2014
comment
И настоящая проблема в том, что я использую неправильный тип фильтра (который не работает с проанализированными данными), как пишет @JohnPetrone. На самом деле мне нужно знать, какой фильтр использовать вместо этого... - person Kamafeather; 08.08.2014