Pull to refresh

Про борьбу с качеством

Reading time 5 min
Views 12K
Ровно через три дня будем раскрывать всем желающим кучу секретов: про настройку, оптимизацию, качество поиска и масштабирование Сфинкса (это все еще такой движок полнотекстового поиска и не только) в разные стороны. Подробности в самом конце поста.

А вот один из секретов про качество поиска начну раскрывать прямо здесь и сейчас. Это новая штука под названием expression ranker, добавленная в версии 2.0.2-beta, (правильный русский перевод еще не придумали), и чуть подробнее я сейчас расскажу про него под катом. Вкратце, оно позволяет задавать свою формулу ранжирования прямо на лету, и даже отдельную для каждого запроса. В общем, эдакий конструктор, который дает возможность каждому попробовать построить свой личный MatrixNet, с четырехмерными шахматами и оперными певицами.

С места в карьер


Эмуляция дефолтного режима ранжирования (для extended режима запросов, это который с синтаксисом) в SphinxQL выглядит, например, вот так:
SELECT *, WEIGHT() FROM myindex WHERE MATCH('hello world')
OPTION ranker=expr('sum(lcs*user_weight)*1000+bm25')

Через SphinxAPI, соотв-но:
$client->SetRankingMode(SPH_RANK_EXPR, "sum(lcs*user_weight)*1000+bm25");


Как оно работает


В формуле ранжирования можно, как и в «обычных» выражениях, использовать любые атрибуты документа и математические функции. Но вдобавок к ним в формуле ранжирования — и только в ней — доступно еще несколько значений и функций, специфичных именно для ранжирования. А именно, факторы уровня документа, факторы уровня поля и агрегирующие всякое по набору полей функции. Все эти дополнительные факторы — это текстовые факторы, те. некие числа, которые зависят от текста документа и запроса, и рассчитываются по ним на лету. Например, число уникальных совпавших в текущем поле или всем документа слов будет именно текстовым фактором. Еще в науке бывают внетекстовые факторы, те. всякие чиселки, которые от текстов не зависят. Это что-нибудь типа количества просмотров страницы, цена товара и прочее подобное. Но такое можно просто положить в атрибут и затем использовать как внутри, так и вне ранжирования. Для справки, факторы еще называют сигналами. Это одно и то же.

Какие есть факторы


Факторы уровня документа есть следующие:
  • bm25, грубая (!) быстрая прикидка статистической функции BM25 для всего документа. Зануда во мне не может промолчать и не сообщить, что после всех огрублений для оптимизации это, на самом деле, скорее BM15, чем канонический BM25. Более понятное объяснение для всех остальных: это некое магическое целое число в диапазоне от 0 до 999, которое растет, если в документе совпало много редких слов и падает, если много частых.
  • max_lcs, максимально возможное значение sum(lcs*user_weight). Используется для эмуляции MATCH_ANY, ну и в целом для всякой нормировки может пригодиться.
  • field_mask, 32-битная маска совпавших полей.
  • query_word_count, число уникальных «включенных» ключевых слов в запросе. Другими словами, общее число уникальных ключевых слов с коррекцией на «исключенные» слова. Например, в запросе (one !two) это будет 1, тк. слово (two) исключается, и никогда не совпадет. Для запроса (one one one !two) тоже 1, тк. уникальное (!) включенное слово все еще только одно. А для запроса (one two three) уже, соотв-но, значение фактора будет 3.
  • doc_word_count, количество уникальных слов, совпавших в текущим документе. Понятно, что никак не должно превышать query_word_count.

Факторы уровня поля есть следующие:
  • lcs, тот самый волшебный фактор, который считает степень «совпадения фразы» между запросом и полем. Формально, длина наибольшей общей в запросе и документе подпоследовательности слов. Равна 0, если в поле вообще ничего не совпало; равна 1, если хоть что-то совпало; и в пределе равне количеству (включенных) слов запроса, если запрос идеально совпал с полем.
  • user_weight, пользовательский вес поля, назначенный через SetFieldWeights() или OPTION field_weights соотв-но.
  • hit_count, число совпавших вхождений ключевых слов. Одно ключевое слово может сгенерировать несколько вхождений. Например, если запрос (hello world) совпал с полем, в котором hello встречается 3 раза, а world 5, то hit_count будет равен 8. Если, однако, в поле фраза hello world встречается ровно 1 раз (несмотря, что слова упоминаются 3 и 5 раз) + вдобавок запрос был «hello world» в кавычках, то hit_count будет равен 2. Всего вхождений слов-то по-прежнему 8, но во втором случае со фразу совпавших из них только 2.
  • word_count, количество уникальных совпавших в поле слов (НЕ вхождений). В обоих предыдущих примерах равно 2, например.
  • tf_idf, сумма TF*IDF по всем совпавшим ключевым словам. TF это просто количество вхождений (Term Frequency), а вот IDF это очередная магическая метрика, которая учитывает «редкость» слова: для суперчастых слов (которые есть в каждом документе) она равна 0, а для уникального слова (1 вхождение в 1 документ во всей коллекции) равна 1.
  • min_hit_pos, самая первая совпавшая в поле позиция ключевого слова. Нумерация начинается с 1. Полезно, например, чтобы ранжировать совпадения в начале поля выше.
  • min_best_span_pos, первая позиция «наилучшего» (имеющего наибольший) lcs поднабора ключевых слов. Нумерация по прежнему с 1.
  • exact_hit, булев флажок, который взводится, если поле совпало полностью. Значения, соотв-но, бывают 0 и 1.

Функция агрегации на данный момент ровно одна, SUM. Выражение внутри функции вычисляется для всех полей, затем результаты суммируются. Этих самых SUM можно делать и несколько, с разными выражениями внутри.
По понятным причинам фактор уровня поля должен встречаться строго внутри функции агрегации. Посчитать-то мы в итоге должны ровно одно число, соотв-но без «привязки» к конкретному полю такие факторы физического смысла не имеют. Факторы уровня документа и атрибуты, разумеется, можно использовать в каком угодно месте выражения.

Как эмулировать существующие ранкеры


Все ранее существовашие ранкеры, на самом деле, в виде новых клевых формул получаются крайне простые. Максимум пара-тройка факторов на ранкер. Список вот:
  • SPH_RANK_PROXIMITY_BM25 = sum(lcs*user_weight)*1000+bm25
  • SPH_RANK_BM25 = bm25
  • SPH_RANK_NONE = 1
  • SPH_RANK_WORDCOUNT = sum(hit_count*user_weight)
  • SPH_RANK_PROXIMITY = sum(lcs*user_weight)
  • SPH_RANK_MATCHANY = sum((word_count+(lcs-1)*max_lcs)*user_weight)
  • SPH_RANK_FIELDMASK = field_mask
  • SPH_RANK_SPH04 = sum((4*lcs+2*(min_hit_pos==1)+exact_hit)*user_weight)*1000+bm25

Эмуляция, разумеется, будет работать медленее, чем использование встроенного ранкера. Все-таки скомпилированный код еще пока быстрее нашей считалки выражений! Однако замедление, чему я не перестаю удивляться, зачастую незначительное. Даже в случае, когда поиск сматчил и должен ранжировать сотни тысячи и миллионы документов у меня на «микро» бенчмарках получались отличия порядка 30-50% (буквально, вместо 0.4 сек со встроенным ранкером около 0.5-0.6 сек с эмуляцией). Подозреваю, если совпадает менее 1-10к документов, то различия вообще не разглядеть.

Что дальше!?


Что со всем этим собственно делать?! С точки зрения возможностей для улучшения качества поиска стало можно довольно много чего. По сути, теперь можно совсем как угодно крутить ранжирование. Появилась кучка новых факторов, которые раньше-то и вообще никогда не считались, а теперь можно крутить прямо на лету. Появилась техническая возможность довольно быстро и легко добавлять по вашему запросу новые факторы — звоните, ряд факторов именно так и был добавлен, по запросам коммерческих клиентов.
Понятно, что это только вершина айсберга, и сразу возникает еще куча вопросов: а как мерить это самое «качество», а как именно крутить формулы, и прочая. Но пишу я медленно, а говорю быстро, поэтому если хотите прослушать этот пост живьем и подробнее во1х, узнать еще вдвое больше всякого про релевантность и качество поиска во2х, а заодно послушать еще несколько докладов про все остальное анонсированное в начале поста, то добро пожаловать на конференцию. (Питер. 04 декабря, воскресенье. Она бесплатная, но нужна регистрация. Сколько-то свободных мест еще осталось, но надо совсем торопиться уже сейчас.)

Всем привет, удачи в борьбе с качеством поиска :)
Tags:
Hubs:
+45
Comments 1
Comments Comments 1

Articles

Information

Website
sphinxsearch.com
Registered
Founded
Employees
Unknown
Location
Россия