О разработке, архитектуре и C++.
Tags: #common, #cpp, #highload и другие можно найти поиском.
Задачки: #poll.
Мои публикации: #pub.
Автор и предложка: @vanyakhodor.
GitHub: dasfex.
Post #512
1.04K
#common
Сидите вы себе спокойно, разрабатываете поиск каких-нибудь объектов. Может это товары, может странички вики, может код. Что угодно. Ваш поиск — качественный keyword search.
Почесали вы репу и решили, что надо улучшать качество. Обучили новую модель, которая умеет понимать СмЫсЛ и выдавать эмбеддинги объектов. Эмбеддинги вы складываете в какую-нибудь векторную БД. Поиск там работает из коробки.
Вопрос: как интегрировать два поиска?
Проблема тут понятная: так как модели поиска работают различно, взять скор каждого объекта и сравнить со скорами объектов из другого поискового движка просто нельзя (это не имеет смысла, ведь в одном движке скор может быть от 0 до 1, а в другом [0; 1000]; считаются по-разному, означают разное).
Что делать?
Reciprocal Rank Fusion (RRF) — алгоритм объединения нескольких списков результатов поиска в один общий. Идея за ним простая: вместо сравнения сырых скоров из разных поисковых систем мы будем смотреть только на позицию айтема в изначальных списках.
Выражается формулой:
doc — документ
N — количество поисковых систем/движков
rank_i(doc) — позиция документа doc в i-м списке
k — некоторая константа, положим 60.
Фактически, чем выше документ находится в разных списках, тем больше его итоговый RRF score.
Давайте быстрый пример. Keyword search выдал (номер-документ):
а vector search:
Тогда
Итоговый результат выглядит так:
D и E можем опустить по некоторому трешхолду или просто потому что они не встретились в результатах обоих движков.
Почему мы взяли k=60?
Понятно, что большее значение k уменьшает влияние первых позиций, а меньшее наоборот: сильнее их награждает.
А 60 это просто значение, использовавшееся в оригинальной статье. Авторы его как-то примерно подобрали и потом отталкивались во всей статье от конкретного значения в формуле.
Плюсы RRF:
• не требует никакого обучения. Простой математический метод.
• очень легко реализовать. Джуна посадите и чекните PR через день.
• неплохо работает даже в самом базовом виде. Без подкручивания k.
• устойчив к разным шкалам score, потому что их не использует.
• очень легко добавлять новые движки.
Минус один, но жирный: не учитывает, на сколько разница между позициями сильная.
Оригинальные скоры для соседних документов в рамках одного движка могут различаться очень сильно, но из-за высокой позиции документ всё ещё может оказаться на высоком месте в итоговом результате.
Фактически RRF — первый бейзлайн для гибридного поиска. Но если хочется качество получше (то есть перестать просто «смешивать» документы, а реально понимать «что лучше показать юзеру»), нужно обучать отдельную модель, которая переранжирует результаты ещё раз. Может она даже будет тяжёлой, но в силу того, что работать ей надо не со всем набором документов, а только с топ-X найденных, это обычно не проблема.
@thisnotes. Patreon, newsletter.
Спасибо Artyom Garkavy и niki4smirn.
Сидите вы себе спокойно, разрабатываете поиск каких-нибудь объектов. Может это товары, может странички вики, может код. Что угодно. Ваш поиск — качественный keyword search.
Почесали вы репу и решили, что надо улучшать качество. Обучили новую модель, которая умеет понимать СмЫсЛ и выдавать эмбеддинги объектов. Эмбеддинги вы складываете в какую-нибудь векторную БД. Поиск там работает из коробки.
Вопрос: как интегрировать два поиска?
Проблема тут понятная: так как модели поиска работают различно, взять скор каждого объекта и сравнить со скорами объектов из другого поискового движка просто нельзя (это не имеет смысла, ведь в одном движке скор может быть от 0 до 1, а в другом [0; 1000]; считаются по-разному, означают разное).
Что делать?
Reciprocal Rank Fusion (RRF) — алгоритм объединения нескольких списков результатов поиска в один общий. Идея за ним простая: вместо сравнения сырых скоров из разных поисковых систем мы будем смотреть только на позицию айтема в изначальных списках.
Выражается формулой:
RRF(doc) = SUM( 1 / (k + rank_i(doc) ), i in [1; N]
doc — документ
N — количество поисковых систем/движков
rank_i(doc) — позиция документа doc в i-м списке
k — некоторая константа, положим 60.
Фактически, чем выше документ находится в разных списках, тем больше его итоговый RRF score.
Давайте быстрый пример. Keyword search выдал (номер-документ):
1 A
2 B
3 C
4 D
а vector search:
1 C
2 A
3 E
4 B
Тогда
RRF(A) = 0.0325
RRF(B) = 0.0317
RRF(C) = 0.0323
RRF(D) = 0.0156
RRF(E) = 0.0159
Итоговый результат выглядит так:
1 A
2 C
3 B
D и E можем опустить по некоторому трешхолду или просто потому что они не встретились в результатах обоих движков.
Почему мы взяли k=60?
Понятно, что большее значение k уменьшает влияние первых позиций, а меньшее наоборот: сильнее их награждает.
А 60 это просто значение, использовавшееся в оригинальной статье. Авторы его как-то примерно подобрали и потом отталкивались во всей статье от конкретного значения в формуле.
Плюсы RRF:
• не требует никакого обучения. Простой математический метод.
• очень легко реализовать. Джуна посадите и чекните PR через день.
• неплохо работает даже в самом базовом виде. Без подкручивания k.
• устойчив к разным шкалам score, потому что их не использует.
• очень легко добавлять новые движки.
Минус один, но жирный: не учитывает, на сколько разница между позициями сильная.
Оригинальные скоры для соседних документов в рамках одного движка могут различаться очень сильно, но из-за высокой позиции документ всё ещё может оказаться на высоком месте в итоговом результате.
Фактически RRF — первый бейзлайн для гибридного поиска. Но если хочется качество получше (то есть перестать просто «смешивать» документы, а реально понимать «что лучше показать юзеру»), нужно обучать отдельную модель, которая переранжирует результаты ещё раз. Может она даже будет тяжёлой, но в силу того, что работать ей надо не со всем набором документов, а только с топ-X найденных, это обычно не проблема.
@thisnotes. Patreon, newsletter.
Спасибо Artyom Garkavy и niki4smirn.
- ❤ 17
- 🔥 4
- 👍 3
- 😁 1












