Оглавление цикла:
Часть третья (вы тут)
Это третья и заключительная статья из цикла, в которой рассмотрим стандартную модель ранжирования документов в Elasticsearch.
Релевантность документов
После того как определено множество документов, которые удовлетворяют параметрам полнотекстового запроса, Elasticsearch рассчитывает метрику релевантности для каждого найденного документа. По значению метрики набор документов сортируется и отдается потребителю.
В Elasticsearch существует несколько моделей ранжирования документов, о которых можно почитать в документации. По умолчанию используется Okapi BM25. Три кита этой модели:
Term frequency (TF) — частотность терма. Чем чаще терм появляется в поле документа, тем он релевантнее;
Inverse document frequency (IDF) — обратная частота употребления терма в документах. Чем больше документов содержат искомый терм в поле, тем меньше значимость этого терма. Данный параметр вводится для снижения веса часто употребляемых слов в выборке;
Normalization by field length — нормализация по длине поля. Если два документа имеют одинаковое количество вхождения искомого терма и документы отличаются по размеру, то наиболее релевантным будет документ, размер которого меньше.
Описание функции ранжирования:
Q (query) — текущий запрос;
???? (document) — текущий документ;
???????? — ????-ый терм;
????(????????, ????) — частота появления терма ???????? в документе ????;
????????????????????????????????????????ℎ — длина поля в термах;
????????????????????????????????????????????????????ℎ — средняя длина поля в термах;
????????????(????????) — обратная частота употребления терма ???????? в документах;
????(???????? ) — кол-во документов, в которых встречается искомый терм;
???????????????????????????????? — количество документов, которые имеют искомое поле;
????1 — коэффициент, который задает порог насыщения по частоте терма (в Elasticsearch равен 1.2);
???? — коэффициент, который усиливает отношение длины документа к средней длине (в Elasticsearch равен 0.75).
Рассмотрим несколько графиков.
Зависимость метрики релевантности от частоты термов при разных значениях k1
Чем больше коэффициент k1, тем выше порог и меньше скорость насыщения. При k1 равным нулю все параметры игнорируются кроме ????????????.
Также на приведенном графике видно, что начиная с некоторого значения частоты, добавление новых термов, которые соответствуют поисковому запросу, не вносит дополнительный вклад в значение метрики релевантности.
Зависимость метрики релевантности от частоты термов при разных значениях отношения длины документы к средней длине
Короткие документы гораздо быстрее достигают порога насыщения, т.к. рассматриваемое отношение находится в знаменателе. Чем больше это отношение, тем меньше значение метрики релевантности.
После достижения "потолка" добавление новых термов, соответствующих поисковому запросу, не вносит дополнительный вклад в значение метрики релевантности.
Задав коэффициент b в ноль, можно полностью убрать влияние данного параметра.
Зависимость IDF от частоты термов при фиксированном количестве документов в выборке
Чем чаще терм встречается в документах, тем меньший вес он будет иметь среди других термов в поисковом запросе.
Пример
Для примера используется индекс с названием kotlin_articles, который имеет стандартные настройки и ровно одну шарду. Если повторить шаги примера для индекса, который имеет больше чем одну шарду, то результат будет отличаться от приведенного. Это связано с тем, что Elasticsearch рассчитывает метрику релевантности в рамках одного шарда.
В рассматриваемый индекс сохраним 5 документов.
Наш поисковый запрос состоит ровно из одного слова — Kotlin. На этом шаге несложно догадаться, в каком порядке будут выданы документы:
Результат ранжирования Elasticsearch:
Значение релевантности находится в после "_score".
А теперь предлагаю проверить, совпадает ли выданное значение метрики с теоретическим. Для проверки возьмем самый релевантный документ, и подставим его параметры в функцию ранжирования.
И мы видим, что значения совпадают!
Для закрепления проверим наши расчеты с помощью Explain API:
{
"_index": "kotlin_articles",
"_id": "2",
"matched": true,
"explanation": {
"value": 0.12335789,
"description": "weight(name:kotlin in 1) [PerFieldSimilarity], result of:",
"details": [
{
"value": 0.12335789,
"description": "score(freq=2.0), computed as boost * idf * tf from:",
"details": [
{
"value": 2.2,
"description": "boost",
"details": []
},
{
"value": 0.087011375,
"description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
"details": [
{
"value": 5,
"description": "n, number of documents containing term",
"details": []
},
{
"value": 5,
"description": "N, total number of documents with field",
"details": []
}
]
},
{
"value": 0.64441884,
"description": "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
"details": [
{
"value": 2,
"description": "freq, occurrences of term within document",
"details": []
},
{
"value": 1.2,
"description": "k1, term saturation parameter",
"details": []
},
{
"value": 0.75,
"description": "b, length normalization parameter",
"details": []
},
{
"value": 5,
"description": "dl, length of field",
"details": []
},
{
"value": 5.6,
"description": "avgdl, average length of field",
"details": []
}
]
}
]
}
]
}
}
В ответе можно узнать функцию ранжирования Okapi BM25, а также какие значения были использованы для расчета.
Это была последняя статья из цикла. Спасибо, что дочитали, если у вас будут какие-то вопросы — добро пожаловать в комментарии.
murkin-kot
Почему тема называется Elastic Search? На самом деле всё сказанное относится к поисковому движку Lucene.
Если бы хотя бы как-то были обозначены границы систем, тогда было бы приемлемо, но по факту имеем рассказ про двигатель на примере автомобиля "Запорожец" и без использования слова "двигатель".
Вот очень простое пояснение.