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

Слияние обратных рангов (Reciprocal Rank Fusion)

Кратко В Apache Doris нет встроенной функции rrf(), но Reciprocal Rank Fusion можно реализовать на обычном SQL. В этом шаблоне ROW_NUMBER() применяется к результатам ранжирования BM25 и векторного ранжирования, после чего значения 1.0 / (60 + rank) суммируются по обоим спискам со стандартной константой сглаживания k = 60. Результат представляет собой единый объединённый список top-K, порядок которого не зависит от согласования оценок BM25 с косинусным расстоянием.

Apache Doris Reciprocal Rank Fusion: шаблон SQL для объединения ранжирования BM25 и векторного ранжирования в Doris с помощью ROW_NUMBER и стандартной формулы 1/(k+rank) без встроенной функции RRF.

Зачем использовать Reciprocal Rank Fusion в Apache Doris?​

Reciprocal Rank Fusion даёт гибридному поиску Apache Doris обоснованный способ по умолчанию объединять результаты BM25 и векторного поиска без калибровки двух несовместимых шкал оценок. Гибридный поиск возвращает два ранжированных списка для одного и того же запроса: один получен при полнотекстовом сопоставлении (оценки BM25 через score()), другой при определении векторного сходства (l2_distance_approximate или inner_product_approximate). Эти оценки используют несовместимые шкалы. BM25 представляет собой положительное число без верхней границы, значение которого зависит от статистики корпуса; косинусное расстояние находится в диапазоне от 0 до 2; расстояние L2 вообще не имеет верхней границы. Сложение или усреднение этих оценок даёт число без обоснованной интерпретации, а нормализация min-max для каждого запроса ненадёжна: один выброс в любом из списков нарушает слияние.

Reciprocal Rank Fusion обходит эту проблему, отбрасывая оценки и оставляя только ранги. У алгоритма всего один настраиваемый параметр, и он хорошо показывает себя в тестах качества поиска с момента публикации Cormack, Clarke и Buettcher в 2009 году.

  • BM25 и векторные расстояния используют разные шкалы; арифметические операции с ними небезопасны.
  • Нормализация min-max перестаёт работать, когда запрос даёт распределение оценок с длинным хвостом.
  • Сервис слияния на стороне приложения становится ещё одним компонентом, который нужно развёртывать и поддерживать в согласованном состоянии с базой данных.

Что такое Reciprocal Rank Fusion в Apache Doris?​

Reciprocal Rank Fusion в Apache Doris представляет собой шаблон SQL, а не встроенную функцию: это алгоритм слияния на основе рангов, выраженный с помощью ROW_NUMBER, FULL OUTER JOIN и стандартной формулы 1/(k+rank). Для документа d, который встречается в ранжированных списках R_1, R_2, ..., R_n, объединённая оценка равна сумме обратных рангов по всем спискам, в которых он присутствует:

score(d) = Σ 1 / (k + rank_i(d))

rank_i(d) обозначает позицию документа d в списке i, отсчитываемую с 1. k задаёт константу сглаживания; значение, рекомендованное Cormack и соавторами и используемое в большинстве промышленных систем, равно 60. Документы, отсутствующие в списке, получают от него нулевой вклад. Затем результаты сортируются по объединённой оценке по убыванию, формируя итоговое ранжирование.

В Apache Doris реализация представляет собой шаблон SQL, а не функцию. Вы пишете два ранжированных подзапроса, один для BM25 и один для ANN, присваиваете каждой строке ROW_NUMBER(), затем выполняете FULL OUTER JOIN и суммируете обратные величины рангов.

Ключевые термины

  • score(): функция вычисления оценки BM25 в Doris для инвертированных индексов. Она работает только в запросе к одной таблице с предикатом MATCH_*, сортировкой ORDER BY по оценке и ограничением LIMIT; в списке выбираемых выражений её нужно использовать без изменений (score() AS s). Ранжирование или округление оценки выполняется во внешнем запросе.
  • l2_distance_approximate / inner_product_approximate: функции расстояния для ANN, использующие векторный индекс Doris (HNSW или IVF).
  • ROW_NUMBER() OVER (ORDER BY ...): присваивает каждой строке набора результатов ранг с отсчётом от 1.
  • k: константа сглаживания RRF. Меньшие значения (20–40) усиливают влияние строк с высокими позициями; большие значения (80+) сглаживают его.

Как работает Reciprocal Rank Fusion в Apache Doris?​

Apache Doris реализует Reciprocal Rank Fusion следующим образом: выполняет два ранжированных поисковых запроса в виде подзапросов, присваивает строкам каждого ROW_NUMBER(), объединяет два списка по идентификатору документа с помощью FULL OUTER JOIN и суммирует 1/(k+rank), чтобы получить итоговый порядок. Следующая последовательность из пяти шагов охватывает поиск, ранжирование, соединение, слияние и ограничение результата.

  1. Выполните два ранжированных поисковых запроса. Подзапрос BM25 фильтрует данные с помощью MATCH_ANY и сортирует их по score() по убыванию. Подзапрос ANN сортирует данные по векторному расстоянию по возрастанию. Каждый ограничен с помощью LIMIT N, где N задаёт размер пула кандидатов (обычно 50–200).
  2. Присвойте ранги в каждом списке. ROW_NUMBER() OVER (ORDER BY ...) нумерует строки 1, 2, 3 внутри каждого подзапроса. Эти числа целочисленные, поэтому их можно безопасно объединять между результатами разных запусков. Для списка BM25 оконную функцию помещают на уровень выше запроса, вычисляющего score(): выражение ROW_NUMBER() OVER (ORDER BY score() DESC) в том же SELECT отклоняется с ошибкой score() function requires WHERE clause with MATCH function, ORDER BY and LIMIT for optimization.
  3. Выполните внешнее соединение двух списков по идентификатору документа. FULL OUTER JOIN сохраняет документы, присутствующие хотя бы в одном списке. Если строка отсутствует с одной стороны, её ранг с этой стороны получает значение NULL.
  4. Сложите обратные величины рангов. Выражение COALESCE(1.0/(60+bm25_rank), 0) + COALESCE(1.0/(60+ann_rank), 0) вычисляет объединённую оценку каждого документа. Отсутствующие ранги дают нулевой вклад, что соответствует исходному определению RRF.
  5. Отсортируйте и ограничьте результат. ORDER BY rrf_score DESC LIMIT K возвращает итоговый список top-K.

Размер пула N имеет значение. Если получать только первые 10 результатов от каждого поискового механизма, документ на 11-м месте в BM25 и на 1-м месте в ANN будет выглядеть как результат, найденный только векторным поиском. Получение 100 кандидатов с каждой стороны служит разумным вариантом по умолчанию; увеличивайте это значение для нагрузок, чувствительных к полноте поиска.

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

Те же четыре строки, что и в примерах Векторный индекс и Гибридный поиск, с текстом комментария в body:

CREATE TABLE docs (
id INT NOT NULL,
embedding ARRAY<FLOAT> NOT NULL,
body STRING NOT NULL,
INDEX idx_body(body) USING INVERTED PROPERTIES("parser"="english"),
INDEX idx_vec(embedding) USING ANN
PROPERTIES("index_type"="hnsw","metric_type"="l2_distance","dim"="8")
) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1;

INSERT INTO docs VALUES
(1, [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8], 'this is about music'),
(2, [0.2,0.1,0.5,0.3,0.9,0.4,0.7,0.1], 'sports news today'),
(3, [0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2], 'latest music trend'),
(4, [0.05,0.06,0.07,0.08,0.09,0.1,0.2,0.3], 'politics update');

SELECT COALESCE(b.id, a.id) AS id,
COALESCE(1.0 / (60 + b.r), 0) + COALESCE(1.0 / (60 + a.r), 0) AS rrf
FROM (
-- BM25 list: score() stays plain here; ROW_NUMBER() ranks it one level up
SELECT id, ROW_NUMBER() OVER (ORDER BY s DESC) AS r
FROM (SELECT id, score() AS s FROM docs
WHERE body MATCH_ANY 'music' ORDER BY s DESC LIMIT 100) bm25_hits
) b
FULL OUTER JOIN (
-- ANN list
SELECT id, ROW_NUMBER() OVER (ORDER BY dist ASC) AS r
FROM (SELECT id, l2_distance_approximate(embedding, [0.1,0.1,0.2,0.2,0.3,0.3,0.4,0.4]) AS dist
FROM docs ORDER BY dist ASC LIMIT 100) ann_hits
) a ON b.id = a.id
ORDER BY rrf DESC LIMIT 5;

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

+------+---------+
| id | rrf |
+------+---------+
| 1 | 0.03224 |
| 3 | 0.03201 |
| 4 | 0.01639 |
| 2 | 0.01587 |
+------+---------+

BM25 ставит документ 3 на первое место, а 1 на второе (только эти два документа содержат "music"); векторный список упорядочен так: 4, 1, 2, 3. Документ 1 занимает второе место в обоих списках, поэтому получает оценку 1/62 + 1/62 ≈ 0.0322 и немного опережает документ 3, который стоит первым по BM25, но последним по расстоянию (1/61 + 1/64 ≈ 0.0320). Документы 4 и 2 присутствуют только в векторном списке и располагаются следом.

Когда следует использовать Reciprocal Rank Fusion в Apache Doris?​

Используйте Reciprocal Rank Fusion в Apache Doris для конвейеров RAG, поиска по Catalog и документам и любых нагрузок, объединяющих BM25 и векторный поиск, когда калибровка абсолютных оценок непрактична. Откажитесь от него при использовании единственного поискового механизма, очень небольших пулов кандидатов, необходимости в откалиброванных вероятностях и в часто выполняемых запросах, где дополнительное соединение увеличивает задержку.

Подходит

  • Конвейеры RAG, которые ищут и по ключевым словам, и по сходству эмбеддингов и которым нужен единый объединённый список top-K для передачи в LLM.
  • Поиск по Catalog или документам, где полнота поиска по ключевым словам и семантического поиска дополняют друг друга и требуется обоснованный вариант ранжирования по умолчанию.
  • Нагрузки, где калибровка абсолютных оценок между поисковыми механизмами непрактична из-за изменений корпуса или распределения запросов.
  • Случаи, когда иначе пришлось бы создавать сервис слияния на уровне приложения; перенос слияния в SQL сокращает путь обработки данных.

Не подходит

  • Нагрузки с единственным поисковым механизмом. Если используется только BM25 или только ANN, сортируйте по исходной оценке и не выполняйте соединение. RRF для одного списка представляет собой лишь монотонное преобразование ранга.
  • Очень небольшие пулы кандидатов (первые 5 или первые 10 результатов с каждой стороны). RRF повышает оценки документов, присутствующих в обоих списках, а для этого оба списка должны быть достаточно длинными. Получайте не менее 50 кандидатов от каждого поискового механизма.
  • Нагрузки, которым нужны откалиброванные вероятности (для пороговой фильтрации, отказа от ответа или последующих моделей затрат). Оценки RRF не являются вероятностями и не имеют абсолютного смысла при сравнении разных запросов. Если нужна калибровка, используйте обученную модель ранжирования.
  • Часто выполняемые запросы, в которых дополнительные подзапросы и соединение увеличивают задержку. Шаблон с предварительной фильтрацией (MATCH_ANY + ORDER BY l2_distance_approximate) возвращает единый ранжированный список за один проход и используется по умолчанию в гибридном поиске.

Настройка k​

Уменьшение k (в сторону 20) увеличивает разрыв между рангами 1 и 5, что полезно, когда один поисковый механизм явно надёжнее. Увеличение k (в сторону 100) делает кривую более пологой и повышает вклад документов, расположенных далеко от начала обоих списков. Измените k один раз, измерьте полноту поиска на размеченном наборе и остановитесь. Подстройка для каждого запроса указывает на необходимость обученной модели ранжирования.

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