#elasticsearch
#elasticsearch
Вопрос:
Я недавно начал работать с elasticsearch, поэтому прошу прощения, если это «базовый» вопрос. Я также находился в процессе переноса наших материалов с ES версии 1.3 на 2.4 (!), Поэтому в процессе некоторые вещи сломались, и запросы / etc., которые раньше работали, больше не работают (или дают «плохие» результаты). Я исправил некоторые из этих проблем, но это тупик.
Я прочитал документы о том, как выполняется оценка релевантности. Мой индекс обрабатывается с помощью маркера шаблона (просто разбивается на слова), затем используется фильтр нижнего регистра и фильтр ngram (минимальная длина 1, максимальная длина 3).
Теперь, если я буду искать букву «a», тогда я должен сначала получить относительно более короткие документы, верно? Так, например, «asian» (который содержит два экземпляра желаемого токена) должен иметь более высокий балл, чем «Astasia-abasia» (у которого шесть), потому что пропорционально больше его токенов равно «a». Пропорциональность учитывается частотой термина и нормой поля. Отлично! Это то, что я хочу. Но …
На самом деле «азиатский» даже не появляется в первых 5000 обращениях! Когда я смотрю ?explain
, я вижу, что пока fieldNorm присутствует, но всегда равно 1. Почему это так? Как я могу это исправить?
Код индекса, который я использую, находится здесь:
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"analysis": {
"analyzer": {
"ngram_analyzer": {
"tokenizer": "pattern_tokenizer",
"filter": [ "lowercase", "ngram_filter" ]
}
},
"tokenizer": {
"pattern_tokenizer": {
"type": "pattern",
"pattern": "[\]\[{}()/ ,:;"amp;] "
}
},
"filter": {
"ngram_filter": {
"type": "ngram",
"min_gram": "1",
"max_gram": "3"
}
}
}
},
"mappings": {
"terms": {
"properties": {
"code": {
"analyzer": "ngram_analyzer",
"search_analyzer": "keyword",
"type": "string",
"norms": {
"enabled": true,
"loading": "eager"
}
},
"codeAbbr": {
"analyzer": "ngram_analyzer",
"search_analyzer": "keyword",
"type": "string",
"norms": {
"enabled": true,
"loading": "eager"
}
},
"term": {
"analyzer": "ngram_analyzer",
"search_analyzer": "keyword",
"type": "string",
"norms": {
"enabled": true,
"loading": "eager"
}
}
}
}
}
}
Я не чувствую, что мне даже нужно указывать атрибут norms (я чувствую, что указанное выше должно быть по умолчанию), но это не имеет значения. Если я выну их или вставлю, ответ будет тот же. Как я могу заставить fieldNorm работать правильно?
Комментарии:
1. Можете ли вы поделиться своим запросом? И результаты вашего объяснения? Также можете ли вы проверить, сколько терминов присутствует в одном из полей? Вы можете выполнить агрегацию терминов в поле и проверить значение «sum_other_doc_count» elastic.co/guide/en/elasticsearch/reference/current /…
2. @jay спасибо за ответ, но, к сожалению, я не получил его, пока не вернулся домой с работы, и не смогу получить точный запрос и результат в субботу. Тем не менее, я считаю, что соответствующая информация содержится в приведенном выше вопросе. Запрос представляет собой запрос соответствия с одним термином «a»
3. Итак, причина, по которой я просил указать количество терминов — fieldNorm рассчитывается как 1 / squareroot (количество терминов). Что означает, что чем больше число терминов, тем меньше fieldNorm. Все ваши поля используют ngrams, что означает, что количество терминов будет v v высоким. Значение 1, которое вы видите — из того, что я читал, значение является увеличением времени индекса по умолчанию на 1 норма поля. Значение хранится в одном байте, поэтому точность теряется.
Ответ №1:
Ответ оказался несколько иным, чем я ожидал; Я надеюсь, что этот ответ поможет кому-то еще сэкономить время, которое я потратил. Я не видел этого нигде в документах, которые я читал, но обнаружил это с помощью экспериментов. Моя очень специфическая проблема может быть решена с помощью токенизатора ngram, а не фильтра ngram, но позвольте мне объяснить, почему это так.
Проблема заключается в том, когда вычисляется fieldNorm, и это одна из причин, почему фильтры ngram и токенизаторы отличаются.
fieldNorm
основано на количестве токенов в документе, используя формулу, указанную в документах 1/sqrt(#tokens)
; в знаменателе может быть или не быть 1, в зависимости от того, кого вы спрашиваете, но это не имеет большого значения для этого вопроса. Важно то, что #tokens
цифра вычисляется после токенизации, но перед фильтрацией.
Насколько я знаю, это важно только для фильтров ngram и edge ngram, поскольку они единственные, которые изменяют количество токенов в документе, поэтому, возможно, именно поэтому это не объясняется в документах. Но вот несколько вариантов использования, чтобы объяснить, почему это важно:
-
Предположим, ваши документы состоят из длинных фраз — может быть, описаний? — и вы маркируете с помощью стандартного токенизатора или чего-то еще. Тогда ваша норма поля основана в основном на количестве слов. Это может быть то, что вы хотите; это зависит от вашего варианта использования. Таким образом, поиск предпочитает более короткие документы с точки зрения количества слов (но использование длинных слов не наказывает ваш поиск). Если вместо этого вы используете токенизатор ngram, норма поля пропорциональна количеству символов; поэтому, если вы используете много маленьких слов, а я использую меньше, но больше слов, наши оценки могут быть одинаковыми. Обычно это не то, что вы хотите.
-
Теперь предположим, что ваши документы состоят из отдельных слов или очень коротких фраз (как у меня). Если вы выполняете токенизацию с помощью стандартного токенизатора, большинство документов будут иметь fieldNorm 1, поскольку они представляют собой отдельные слова. Однако я хочу, чтобы в моем поиске приоритет отдавался более коротким словам (в качестве приближения к «общим словам»), так что это не помогает. Вместо этого я буду использовать токенизатор ngram, поэтому более длинные слова будут помещены на дно, а более короткие слова всплывут наверх.