Перейти к содержимому
Последнее обновление

Оценка релевантности BM25

Кратко Apache Doris ранжирует результаты полнотекстового поиска с помощью BM25 — того же алгоритма оценки, который используют Lucene и Elasticsearch. Добавьте score() в SELECT, укажите предикат MATCH_* в предложении WHERE и отсортируйте результаты по оценке с помощью ORDER BY, задав LIMIT. Планировщик Apache Doris переносит вычисление top-K в инвертированный индекс и сначала возвращает наиболее релевантные строки.

Оценка релевантности BM25 в Apache Doris: ранжирование результатов полнотекстового поиска по релевантности BM25 позволяет SQL-запросам сортировать совпадения так же, как это делает поисковая система.

Зачем использовать оценку BM25 в Apache Doris?​

Оценка BM25 в Apache Doris позволяет ранжировать совпадения полнотекстового поиска и получать top-K непосредственно в SQL. Так из корпуса в миллион строк можно выбрать десять лучших результатов без отдельной поисковой системы. Фильтры по равенству показывают, какие строки соответствуют условию. Но они не показывают, какие совпадения наиболее удачны. Запрос вида WHERE content MATCH_ANY 'apache doris real-time analytics' к таблице журналов с миллионом строк легко может вернуть 50,000 совпадений, хотя пользователю нужны только десять лучших. Без оценки релевантности у базы данных нет подходящего способа выбрать эти десять строк:

  • При сортировке по дате идеально подходящий результат за прошлый год окажется далеко внизу.
  • При сортировке по произвольному столбцу пользователю достанутся случайные результаты.
  • Если вычислять релевантность в приложении, придётся построить половину поисковой системы поверх хранилища данных.

BM25 решает эту задачу внутри SQL. Apache Doris присваивает каждой подходящей строке оценку с учётом того, как часто в ней встречаются термы запроса, насколько редки эти термы во всей таблице и какова длина текста строки. Сортировка по этой оценке даёт ранжирование как в поисковой системе с помощью обычного SELECT.

Что такое оценка BM25 в Apache Doris?​

Оценка BM25 в Apache Doris — это доступная через SQL реализация функции ранжирования по релевантности BM25 (Best Matching 25) из семейства TF-IDF. Функция принимает терм запроса и документ и возвращает положительное число: чем оно больше, тем выше релевантность. Оценка зависит от трёх факторов. Строки, в которых терм встречается чаще, получают более высокую оценку. Редкие термы имеют больший вес, чем распространённые. Кроме того, оценка длинных строк нормализуется в сторону уменьшения, чтобы строка из 200 слов не получала автоматически более высокую оценку, чем строка из 20 слов с тем же содержанием.

Apache Doris предоставляет доступ к BM25 через SQL-функцию score(). Инвертированный индекс уже хранит частоты термов, частоты документов с этими термами и длины полей, необходимые для формулы. Поэтому, если индекс создан, дополнительное сканирование для вычисления оценки не требуется.

Основные термины

  • score(): скалярная функция Apache Doris, которая возвращает оценку релевантности BM25 текущей строки относительно предикатов MATCH_* запроса. Возвращает FLOAT.
  • TF (частота терма): количество вхождений терма запроса в строку.
  • IDF (обратная частота документа): мера того, насколько редко терм встречается в таблице. Распространённые слова получают низкую оценку, редкие — высокую.
  • k1 и b: настроечные константы BM25. Apache Doris использует k1 = 1.2 и b = 0.75 — значения по умолчанию в Lucene. В настоящее время они недоступны в виде переменных сеанса.

Как работает оценка BM25 в Apache Doris?​

Apache Doris вычисляет BM25 внутри компонента чтения инвертированного индекса: планировщик распознаёт сочетание score() + MATCH_* + ORDER BY + LIMIT, BE оценивает строки при сканировании списков вхождений, а ограниченная минимальная куча размером LIMIT сохраняет только top-K.

  1. Инвертированный индекс сохраняет статистику. При загрузке данных в столбец с инвертированным индексом с токенизацией, использующим, например, парсеры english, standard или chinese, Apache Doris сохраняет словарь термов, частоты термов для каждой строки и длины полей. Та же статистика, которая обеспечивает фильтрацию MATCH_*, используется и для BM25.
  2. Планировщик распознаёт структуру запроса для оценки. Если запрос содержит score() в SELECT, предикат MATCH_* в WHERE и ORDER BY score() с LIMIT, Nereids преобразует план, перенося вычисление оценок top-K на уровень хранения. Если использовать score() вне этой структуры, Apache Doris завершит запрос с ошибкой score() function requires WHERE clause with MATCH function, ORDER BY and LIMIT for optimization. Это ограничение защищает от случайного вычисления оценок для всех строк таблицы с миллиардом строк.
  3. BE вычисляет оценки при сканировании. Компонент чтения инвертированного индекса обходит списки вхождений для каждого терма запроса. Для каждой строки-кандидата он вычисляет IDF * (tf * (k1 + 1)) / (tf + k1 * (1 - b + b * |d| / avgdl)), где |d| — длина строки в токенах, а avgdl — средняя длина по таблице. В запросах с несколькими термами оценки отдельных термов суммируются.
  4. Куча сохраняет top-K. BE поддерживает ограниченную минимальную кучу размером LIMIT, поэтому ему не требуется хранить в памяти весь набор совпадений. Вместо того чтобы сначала оценить 50,000 строк, а затем отсортировать их, он вычисляет оценки по мере чтения и сохраняет только десять лучших результатов.
  5. Apache Doris возвращает ранжированные строки. FE объединяет уже отсортированные результаты top-K от каждого tablet и возвращает итоговый результат.

Быстрый старт​

CREATE TABLE articles (
id BIGINT,
content TEXT,
INDEX idx_content(content) USING INVERTED PROPERTIES("parser" = "english")
) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1;

INSERT INTO articles VALUES
(1, 'apache doris is a real-time analytics database'),
(2, 'real-time analytics on streaming data'),
(3, 'a guide to apache kafka');

SELECT id, content, score() AS relevance
FROM articles
WHERE content MATCH_ANY 'apache doris analytics'
ORDER BY relevance DESC
LIMIT 3;

Ожидаемый результат

+----+----------------------------------------------------+-----------+
| id | content | relevance |
+----+----------------------------------------------------+-----------+
| 1 | apache doris is a real-time analytics database | 1.871290 |
| 2 | real-time analytics on streaming data | 0.575364 |
| 3 | a guide to apache kafka | 0.287682 |
+----+----------------------------------------------------+-----------+

Строка 1 получает наивысшую оценку, поскольку содержит все три терма запроса. Строка 2 содержит один редкий терм (analytics). Строка 3 содержит только apache, самый распространённый терм в этом корпусе, поэтому её оценка самая низкая. Абсолютные значения сами по себе ничего не означают. Важен порядок строк в пределах этого набора результатов.

Когда следует использовать оценку BM25 в Apache Doris?​

Оценка BM25 в Apache Doris подходит для ранжирования top-K в полнотекстовом поиске и для текстовой составляющей гибридного поиска. Она не подходит для поиска по точному равенству, агрегаций по релевантности или сравнения оценок разных запросов.

Подходящие сценарии

  • Полнотекстовый поиск top-K по журналам, документам, статьям, описаниям товаров или любому текстовому столбцу с инвертированным индексом с токенизацией.
  • Текстовая составляющая запроса гибридного поиска, объединяемая с векторным сходством через SQL ORDER BY или RRF.
  • Отказ от отдельного кластера Elasticsearch, единственная задача которого — ранжировать совпадения по данным, уже хранящимся в Doris.
  • Запросы с несколькими термами, в которых пользователям важно найти лучшее совпадение, а не просто любое совпадение.

Неподходящие сценарии

  • Поиск по точному равенству. Инвертированный индекс без токенизации не вычисляет оценки. Используйте = или IN и полностью исключите score().
  • Агрегации по результатам с оценками. Apache Doris не допускает score() внутри GROUP BY, внутри агрегатных функций и в любом плане без ORDER BY score() LIMIT. Если нужна аналитика по релевантности, сначала материализуйте top-K, а затем выполните агрегацию по полученному набору результатов.
  • Сравнение оценок разных запросов. BM25 зависит от корпуса и запроса. Оценка 3.0 в одном запросе и 3.0 в другом имеют разный смысл. Вместо этого используйте объединение на основе рангов, например RRF. См. Reciprocal Rank Fusion.
  • Настройка k1 и b для каждого запроса. Apache Doris использует значения по умолчанию в Lucene и в настоящее время не предоставляет эти константы как параметры времени выполнения. Если вашей рабочей нагрузке действительно нужна индивидуальная настройка, создайте issue, вместо того чтобы обходить ограничение с помощью самостоятельно реализованной оценки.
  • Чисто векторное ранжирование. Если запрос звучит как «найти 10 ближайших эмбеддингов без каких-либо ограничений по ключевым словам», используйте функцию расстояния ANN и не применяйте BM25.

Дополнительные материалы​