Текстовая релевантность

Рейтинг: 78.5% · 14 голосов
Полный курс об устройстве веб-поиска: обход, индексирование, факторы ранжирования, нейропоиск, поведенческие сигналы, антиспам, SEO. 23 модуля по главам с разбором и обсуждением.
Ответить
Аватара пользователя
kirill_ir
Сообщения: 25
Зарегистрирован: 11 май 2026, 05:31

Текстовая релевантность

Сообщение kirill_ir »

Оглавление курса (23)
  1. Введение
  2. Теоретический фундамент (Information Retrieval)
  3. Краулинг (обход)
  4. Идентичность документа: каноникализация и дубли
  5. Индексирование и хранение
  6. Обработка и понимание запроса
  7. Текстовая релевантность (вы здесь)
  8. Анализ ссылочного графа
  9. Таксономия факторов ранжирования
  10. Машинное обучение ранжированию (Learning-to-Rank)
  11. Нейросетевой поиск (Neural IR)
  12. Поведенческие сигналы и клик-модели
  13. Каскад ранжирования и обслуживание (serving)
  14. Инфраструктура и распределённое обслуживание
  15. Метапоиск и федерация источников
  16. Группировка, схлопывание, разнообразие
  17. Постранжирование, антиспам и качество выдачи
  18. Свежесть и реалтайм
  19. Локализация, гео и персонализация
  20. Измерение качества и эксперименты
  21. SEO: оптимизация под факторы
  22. Этика, приватность и борьба со злоупотреблениями
  23. Capstone: сквозной проект
Часть III · ~8 ч · Сложность: (средний) · Пререквизиты: Модуль 1, 4
Обзор модуля

Текстовая релевантность — это попытка ответить на вопрос «насколько хорошо слова документа объясняют слова запроса», опираясь только на сам текст, без ссылочного графа, поведения пользователей и машинного обучения. Это самый старый и самый понятный класс факторов ранжирования, и одновременно — фундамент, поверх которого надстраивается всё остальное. В сквозном конвейере «обход → индекс → факторы → ранжирование → выдача → постобработка → измерение» этот модуль живёт на стыке индекса (Модуль 4) и факторов (Модуль 8): мы уже умеем находить документы, содержащие термины запроса, и теперь учимся присваивать им числовую оценку соответствия.

В Модуле 1 вы познакомились с булевой и векторной моделями и общей идеей tf-idf. Здесь мы делаем шаг к промышленным методам: разбираем вероятностную модель BM25 и её строгий вывод, расширяем её на документы со структурой (BM25F), затем выходим за пределы «мешка слов» — учитываем покрытие запроса, близость и порядок слов (proximity), фразовость, зональные веса полей и, наконец, внешние тексты-источники (якорный текст и тексты ссылающихся страниц). Именно эти сигналы образуют признаки нижнего уровня каскада ранжирования (L0–L1, Модуль 12), которые потом подаются в обучаемые модели (Модуль 9) и нейропоиск (Модуль 10).

После модуля вы сможете: вывести формулу BM25 из вероятностных соображений и руками посчитать скор для мини-корпуса; объяснить, как k1 и b управляют насыщением и нормировкой длины; настроить веса полей в BM25F; реализовать оценку близости слов и фраз; и грамотно отделить «честные» текстовые сигналы от того, что выглядит как переспам и ловится антиспамом (Модуль 16).
Интуиция. Текстовая релевантность отвечает на вопрос «о том ли этот документ?», а не «хорош ли он?». Авторитетность, свежесть, удобство — это другие модули. Здесь мы измеряем именно тематическое совпадение текста с запросом.
Как читать по трекам
  • Студент CS — обязательно всё. Главы 6.1 (вывод BM25) и 6.2 (модели близости) — ядро теории IR. Прорешайте обе лабы руками.
  • Инженер поиска/ML — обязательно всё, особенно инженерные заметки про предвычисление IDF, позиционные постинги и стоимость proximity. Эти признаки вы будете считать в L0–L1.
  • SEO-специалист — обязательно SEO-врезки во всех главах и главы 6.3–6.4 целиком (title, заголовки, якоря). Вывод формулы в 6.1 — обзорно, но прочитайте раздел про насыщение и переспам.
  • Смешанный/руководитель — Обзор модуля, интуиции, заблуждения и итоги. Формулы можно пролистать, но запомните роль k1, b и идею насыщения.
Карта модуля
  • 6.1. BM25/BM25F и насыщение частоты термина, роль k1 и b (средний)
  • 6.2. Покрытие запроса, близость слов (proximity), порядок и фразовость (средний)
  • 6.3. Зональная релевантность и веса полей (title/тело/URL/заголовки) (средний)
  • 6.4. Якорный текст и тексты-источники как сигнал релевантности (средний)
Глава 6.1. BM25/BM25F и насыщение частоты термина, роль k1 и b (средний)

Цели обучения

После главы студент сможет:
  • Объяснить, почему вклад частоты термина должен насыщаться, а не расти линейно.
  • Вывести формулу BM25 из вероятностной модели релевантности и из соображений насыщения.
  • Объяснить роль и предельные случаи параметров k1 (насыщение) и b (нормировка длины).
  • Руками посчитать BM25 для небольшого корпуса.
  • Обобщить формулу до BM25F для документов с несколькими полями.
Конспект

Базовая идея текстового ранжирования: документ d тем релевантнее запросу q, чем чаще в нём встречаются слова запроса — но с двумя поправками. Первая: слово должно быть редким (частые слова вроде «и», «как» почти ничего не различают). Вторая: вклад частоты должен насыщаться (выходить на плато). BM25 — это формула, которая аккуратно совмещает обе поправки и добавляет третью: поправку на длину документа.

Шаг 1. Почему частота должна насыщаться
Интуиция. Если слово «ипотека» встретилось в документе 1 раз против 0 — это огромный скачок смысла: документ вообще «про это». 50 раз против 49 — почти ничего нового: и так понятно, что документ про ипотеку. Вклад частоты должен резко расти у нуля и выходить на плато при больших значениях.
Линейная функция tf (как в наивном tf-idf) этого не даёт: 50 вхождений она оценивает в 50 раз весомее одного. Нам нужна вогнутая, ограниченная сверху функция от tf. Простейшее семейство с нужным поведением:

Код: Выделить всё

saturation(tf) = tf / (tf + k1)
При tf → 0 функция ≈ tf/k1 (почти линейна у нуля), при tf → ∞ стремится к 1 (плато). Параметр k1 > 0 задаёт, как быстро наступает насыщение: маленький k1 — насыщение почти мгновенное (важен сам факт вхождения), большой k1 — функция долго остаётся линейной (важно количество).
Пример. Пусть k1 = 1.2. Тогда saturation(1) = 1/2.2 ≈ 0.45, saturation(2) ≈ 0.63, saturation(5) ≈ 0.81, saturation(50) ≈ 0.98. Переход от 1 к 2 даёт +0.18, а от 5 к 50 — всего +0.17 при росте частоты в 10 раз. Это и есть насыщение.
В BM25 используют слегка нормированный вариант, чтобы коэффициент при насыщенном tf был интерпретируем:

Код: Выделить всё

tf · (k1 + 1)
─────────────
  tf + k1
Множитель (k1 + 1) в числителе не меняет порядок документов (это общий масштаб), но делает так, что при tf = 1 значение равно (k1+1)/(1+k1) = 1 — удобно для сравнения.

Шаг 2. Поправка на длину документа
Интуиция. В длинном документе любое слово встречается чаще просто потому, что слов много, а не потому, что документ «более про это». Длину надо штрафовать — но не всегда одинаково.
Введём нормировку длины. Пусть |d| — длина документа (число токенов), avgdl — средняя длина документа в корпусе. Заменим в знаменателе насыщения k1 на k1 · B, где

Код: Выделить всё

B = (1 − b) + b · |d| / avgdl,   0 ≤ b ≤ 1
Смысл: для документа средней длины |d| = avgdl множитель B = 1 (штрафа нет). Длиннее среднего → B > 1 → знаменатель больше → вклад термина меньше. Параметр b регулирует силу нормировки:
  • b = 0: B = 1 всегда, длина игнорируется полностью.
  • b = 1: полная нормировка, вклад делится пропорционально длине.
  • типичное значение b ≈ 0.75: частичная нормировка.
Внимание. Полная нормировка (b = 1) не всегда хороша: бывают честно длинные релевантные документы (подробная статья). b ≈ 0.75 — компромисс, найденный эмпирически, но его стоит подбирать под корпус (см. лабу и Модуль 19).
Шаг 3. IDF — вес редкости термина (вероятностный вывод)

Теперь — почему редкие слова важнее. BM25 происходит из вероятностной модели релевантности (Probabilistic Relevance Framework). Кратко идея вывода.

Ранжируем документы по шансу быть релевантными. По теореме Байеса логарифм отношения шансов «релевантен / не релевантен» при независимости терминов раскладывается в сумму по терминам запроса. Для каждого термина t вклад в лог-шанс — это вес релевантности Робертсона–Спарк Джонс (RSJ):

Код: Выделить всё

w(t) = log[ (r + 0.5)(N − n − R + r + 0.5) / ((n − r + 0.5)(R − r + 0.5)) ]
где N — всего документов, n — документов с термином t, R — релевантных документов, r — релевантных с термином t. Это формула «с обратной связью», когда мы знаем разметку релевантности.

В типичном веб-поиске разметки нет: считаем R = 0, r = 0 (ничего не знаем заранее). Подстановка даёт IDF в форме BM25:

Код: Выделить всё

        N − n + 0.5
IDF(t) = log ───────────
          n + 0.5
Интуиция. IDF тем больше, чем меньше документов содержит термин. «Сглаживание» +0.5 страхует от деления на ноль и от отрицательных всплесков. Эта форма может стать слегка отрицательной для сверхчастых терминов (n > N/2) — на практике часто берут max(0, IDF) или вариант log((N − n + 0.5)/(n + 0.5) + 1), который всегда положителен.
Шаг 4. Полная формула BM25 (сборка)

Соединяя три части — вес редкости (IDF), насыщенную частоту и нормировку длины — получаем итоговый скор документа d для запроса q:

Код: Выделить всё

                          tf(t,d) · (k1 + 1)
BM25(d, q) =  Σ   IDF(t) · ───────────────────────────────────────
            t ∈ q          tf(t,d) + k1 · (1 − b + b · |d| / avgdl)
где:
  • tf(t,d) — частота термина t в документе d;
  • IDF(t) — вес редкости термина (формула выше);
  • |d| — длина документа в токенах; avgdl — средняя длина по корпусу;
  • k1 — параметр насыщения (типично 1.2…2.0);
  • b — параметр нормировки длины (типично 0.75).
Заметка про повторы термина в запросе. Если термин встречается в запросе несколько раз, добавляют множитель qtf·(k3+1)/(qtf+k3) — насыщение по частоте в запросе. Для коротких веб-запросов им обычно пренебрегают (qtf = 1).
Предельные случаи (проверка понимания формулы)

Код: Выделить всё

Случай                 |  Что происходит               |  Почему
-----------------------+-------------------------------+------------------------------------------------+-----+--------
b = 0                  |  длина документа не влияет    |  B = 1, нормировка отключена
b = 1                  |  максимальный штраф за длину  |  B =                                           |  d  |  /avgdl
k1 → 0                 |  важен только факт вхождения  |  насыщение мгновенное: tf любой → вклад ≈ IDF
k1 → ∞                 |  насыщения почти нет          |  функция ≈ линейна по tf (как сырой tf-idf)
n мал (редкий термин)  |  большой вклад                |  высокий IDF
n ≈ N (стоп-слово)     |  вклад ≈ 0 или отрицателен    |  IDF ≈ 0
Пример расчёта BM25 (полный)

Корпус из N = 4 документов. Запрос q = {ипотека, ставка}. Берём k1 = 1.2, b = 0.75.

Код: Выделить всё

Док  |  Текст (упрощённо, токены)                          |     |  d  |     |  tf(ипотека)  |  tf(ставка)
-----+-----------------------------------------------------+-----+-----+-----+---------------+------------
D1   |  ипотека ставка ставка банк                         |  4  |  1  |  2
D2   |  ипотека ипотека ипотека условия дом кредит ставка  |  7  |  3  |  1
D3   |  дом дом ремонт                                     |  3  |  0  |  0
D4   |  ставка налог                                       |  2  |  0  |  1
Средняя длина: avgdl = (4 + 7 + 3 + 2) / 4 = 4.0.

Документная частота (df):
  • ипотека встречается в D1, D2 → n = 2.
  • ставка встречается в D1, D2, D4 → n = 3.
IDF (форма log((N − n + 0.5)/(n + 0.5)), натуральный логарифм):
  • IDF(ипотека) = ln((4 − 2 + 0.5)/(2 + 0.5)) = ln(2.5/2.5) = ln(1) = 0.0
  • IDF(ставка) = ln((4 − 3 + 0.5)/(3 + 0.5)) = ln(1.5/3.5) = ln(0.4286) ≈ −0.847
Внимание. На таком крошечном корпусе оба термина встречаются больше чем в половине документов, поэтому «сырой» IDF близок к нулю или отрицателен — это артефакт малого N. Чтобы пример был содержательным, используем неотрицательный вариант IDF(t) = ln(1 + (N − n + 0.5)/(n + 0.5)):
- IDF(ипотека) = ln(1 + 1.0) = ln(2.0) ≈ 0.693
- IDF(ставка) = ln(1 + 0.4286) = ln(1.4286) ≈ 0.357
Насыщенная частота с нормировкой. Обозначим S(tf, |d|) = tf·(k1+1) / (tf + k1·(1 − b + b·|d|/avgdl)), где k1 = 1.2, b = 0.75.

Множитель длины B(|d|) = 0.25 + 0.75·|d|/4:
  • B(4) = 0.25 + 0.75·1.0 = 1.000
  • B(7) = 0.25 + 0.75·1.75 = 0.25 + 1.3125 = 1.5625
  • B(2) = 0.25 + 0.75·0.5 = 0.625
Документ D1 (|d|=4, B=1.0, k1·B = 1.2):
  • термин ипотека, tf=1: S = 1·2.2 / (1 + 1.2) = 2.2/2.2 = 1.000 → вклад 0.693·1.000 = 0.693
  • термин ставка, tf=2: S = 2·2.2 / (2 + 1.2) = 4.4/3.2 = 1.375 → вклад 0.357·1.375 = 0.491
  • BM25(D1) = 0.693 + 0.491 = 1.184
Документ D2 (|d|=7, B=1.5625, k1·B = 1.875):
  • ипотека, tf=3: S = 3·2.2 / (3 + 1.875) = 6.6/4.875 = 1.354 → вклад 0.693·1.354 = 0.938
  • ставка, tf=1: S = 1·2.2 / (1 + 1.875) = 2.2/2.875 = 0.765 → вклад 0.357·0.765 = 0.273
  • BM25(D2) = 0.938 + 0.273 = 1.211
Документ D3 — нет ни одного термина запроса → BM25(D3) = 0.

Документ D4 (|d|=2, B=0.625, k1·B = 0.75):
  • ипотека, tf=0: вклад 0
  • ставка, tf=1: S = 1·2.2 / (1 + 0.75) = 2.2/1.75 = 1.257 → вклад 0.357·1.257 = 0.449
  • BM25(D4) = 0.449
Итоговое ранжирование: D2 (1.211) > D1 (1.184) > D4 (0.449) > D3 (0).
Разбор. D2 обошёл D1, несмотря на то что в нём оба слова и он длиннее: три вхождения «ипотека» (редкий, более весомый термин) перевесили, хотя насыщение и штраф за длину частично это съели. Обратите внимание: разница D2 и D1 крошечная (0.027) — если поднять b, штраф за длину у D2 (длина 7 против среднего 4) усилится, и порядок может перевернуться. Это иллюстрирует, как b управляет балансом.
BM25F — версия для документов со структурой

Реальный документ — не плоский «мешок слов», а набор полей (зон): title, тело, URL, заголовки H1…H6, мета-описание, якорный текст входящих ссылок (Глава 6.4). Вхождение в title должно весить больше, чем в подвале страницы.

Наивный подход — посчитать BM25 по каждому полю и взвешенно сложить скоры — работает плохо: насыщение применяется к каждому полю отдельно, и одно вхождение в title + одно в теле дают непропорционально много. Правильный приём BM25F — сначала собрать взвешенную псевдочастоту по всем полям, и только потом применить насыщение один раз.

Пусть у документа поля f с весами w_f, длинами |d_f|, средними длинами поля avgdl_f и собственными параметрами нормировки b_f. Тогда:

Код: Выделить всё

                w_f · tf(t, f)
tf~(t,d) =  Σ   ─────────────────────────────────
          f      1 − b_f + b_f · |d_f| / avgdl_f
И затем единое насыщение:

Код: Выделить всё

                       tf~(t,d)
BM25F(d,q) =  Σ  IDF(t) · ─────────────────
            t∈q          tf~(t,d) + k1
Интуиция. BM25F нормирует длину внутри каждого поля (короткий title не штрафуется по меркам длинного тела), затем складывает вклады полей с весами w_f, и только в самом конце «гасит» суммарную частоту насыщением. Так одно сильное вхождение в title повышает скор ощутимо, но два десятка повторов в title уже почти не помогают.
Инженерная заметка. IDF в BM25F обычно считают по всему документу (по объединению полей), а не по каждому полю — иначе df для одного и того же термина был бы несогласован между зонами. Хранить нужно tf по каждому полю отдельно (позиционно-зональный постинг, Модуль 4) и |d_f| по каждому полю. Веса w_f и параметры b_f подбираются как гиперпараметры (Модуль 19) либо обучаются как признаки в LTR (Модуль 9).
SEO-врезка. Из BM25F следуют три практических вывода. (1) Title важен — вес поля title в реальных системах выше тела, поэтому ключевой смысл запроса должен быть в заголовке страницы. (2) Насыщение реально — добавить ключевое слово 1–2 раза в важные зоны полезно, набивать его 30 раз бессмысленно (плато) и опасно (антиспам, Модуль 16). (3) Нормировка длины означает, что «разбавление» ключевого слова тоннами нерелевантного текста снижает его вес — релевантный плотный текст выигрывает у «простыни ради объёма», но и переоптимизированная короткая страница ловится фильтрами. Золотая середина — естественная плотность.
Частые заблуждения
Заблуждение. «Чем чаще ключевое слово в тексте, тем выше позиция.» Неверно: вклад частоты насыщается (функция tf/(tf+k1·B) выходит на плато), а сверх некоторого порога переспам распознаётся антиспам-правилами (Модуль 16) и может понизить документ. Линейного выигрыша от частоты не существует уже на уровне базовой формулы.
Заблуждение. «BM25 — это просто tf-idf.» Нет: tf-idf линеен по частоте и обычно не нормирует длину разумно; BM25 добавляет насыщение (k1), управляемую нормировку длины (b) и вероятностно обоснованный IDF. Это качественно другая, эмпирически гораздо более сильная модель.
Заблуждение. «Чтобы усилить поле title, надо считать BM25 по title и прибавить к BM25 по телу.» Это и есть наивная ошибка, которую решает BM25F: складывать надо частоты до насыщения, а не готовые скоры, иначе насыщение работает некорректно.
Лаба / практика

Задача. Реализуйте BM25 и BM25F поверх обратного индекса и исследуйте параметры. Время ~60 мин.

Входные данные. Мини-корпус из 6 коротких документов (5–15 слов), у каждого есть поле title и поле body. Запрос из 2–3 слов.

Шаги.
  1. Постройте обратный индекс: для каждого термина — список (doc_id, tf_title, tf_body); посчитайте df, |d_title|, |d_body|, avgdl_title, avgdl_body.
  2. Реализуйте IDF(t) (неотрицательный вариант) и функцию bm25(doc, query, k1, b).
  3. Посчитайте ранжирование при k1=1.2, b=0.75. Сверьте с эталоном (дайте порядок руками для одного запроса).
  4. Эксперимент с b: прогоните b ∈ {0, 0.5, 0.75, 1.0} и зафиксируйте, как меняется позиция самого длинного документа. Объясните.
  5. Эксперимент с k1: прогоните k1 ∈ {0.1, 1.2, 5, 50} для документа, где ключевое слово повторено 5 раз. Покажите, как растёт вклад и где наступает плато.
  6. Реализуйте BM25F с весами w_title = 3, w_body = 1. Покажите, что документ, где запрос только в title, поднимается выше документа с тем же словом только в body.
Критерий «сделано». Порядок при базовых параметрах совпал с эталоном; построены и словесно объяснены две зависимости (от b и от k1); BM25F демонстрирует приоритет title; вы можете объяснить, почему складывать частоты, а не скоры.

Контрольные вопросы
  1. Почему вклад частоты термина в BM25 должен быть вогнутой ограниченной функцией, а не линейной? Приведите числовой пример насыщения.
  2. Что произойдёт со скором при b = 0? А при b = 1? Когда b = 1 навредит?
  3. Какому поведению соответствуют предельные случаи k1 → 0 и k1 → ∞?
  4. Откуда в формуле IDF берётся слагаемое +0.5 и почему «сырой» вариант может быть отрицательным?
  5. Почему в BM25F насыщение применяют один раз к сумме взвешенных частот, а не к каждому полю отдельно?
  6. У вас два документа с одинаковым tf ключевого слова, но один вдвое длиннее. Как и почему изменится их относительный скор при b = 0.75?
  7. Как из вероятностной модели релевантности получается, что вклады терминов складываются? Какое допущение за этим стоит?
  8. Почему набивание ключевого слова в 30 раз почти не повышает BM25, но может понизить документ в целом?
Глава 6.2. Покрытие запроса, близость слов (proximity), порядок и фразовость (средний)

Цели обучения

После главы студент сможет:
  • Отличить «мешок слов» от моделей, учитывающих взаимное расположение терминов.
  • Объяснить и формализовать покрытие запроса (сколько терминов вообще нашлось).
  • Реализовать оценку близости (proximity) через минимальное окно и через расстояния между парами.
  • Объяснить, чем фразовое совпадение и совпадение порядка сильнее разрозненного.
  • Оценить вычислительную стоимость proximity и понять, где её считают в каскаде.
Конспект

BM25 — это «мешок слов» (bag of words): он не знает, стоят ли слова запроса рядом или разбросаны по разным абзацам. Но для пользователя «дешёвый ремонт квартиры» и документ, где «дешёвый» в шапке, «ремонт» в середине, а «квартиры» в подвале — это не то же самое, что фраза «дешёвый ремонт квартиры» в одном предложении. Эта глава — про сигналы, которые BM25 игнорирует.

Покрытие запроса (query coverage)
Интуиция. Документ, в котором нашлись все слова запроса, почти всегда лучше документа, где нашлась только половина — даже если у второго эти слова очень частые. Полнота совпадения важнее интенсивности.
Формально покрытие — доля (или число) уникальных терминов запроса, присутствующих в документе:

Код: Выделить всё

coverage(d, q) = |{t ∈ q : tf(t,d) > 0}| / |q|
Чистый BM25 учитывает это лишь косвенно (документ с большим числом разных терминов набирает больше слагаемых), но не гарантирует приоритет полного покрытия: один очень частый редкий термин может «перевесить» наличие всех остальных. Поэтому на практике покрытие добавляют как отдельный сигнал или режим работы:
  • Жёсткое требование (AND-семантика): документ обязан содержать все термины (или все «обязательные» после анализа запроса, Модуль 5). Документы с неполным покрытием либо отсекаются, либо уходят в хвост.
  • Мягкое (OR с бонусом): допускаем неполное покрытие, но добавляем монотонно растущий бонус за число найденных терминов.
  • Опциональные термины: после понимания запроса (Модуль 5) часть слов помечается как необязательная (стоп-слова, синонимы), и покрытие считается только по «ядру».
Инженерная заметка. Покрытие тесно связано с отбором кандидатов на уровне L0 (Модуль 12): часто индекс сначала достаёт документы по пересечению постингов (AND), и только если их мало — расширяет до OR. Это и реализация семантики покрытия, и оптимизация: пересечение коротких списков дешевле.
Близость слов (proximity)

Даже при полном покрытии важно, насколько кучно расположены термины. Для этого нужен позиционный индекс (Модуль 4): постинг хранит не только (doc_id, tf), но и список позиций каждого вхождения.

Две распространённые формализации близости.

(а) Минимальное покрывающее окно (span). Найдём кратчайший отрезок текста, содержащий хотя бы по одному вхождению каждого термина запроса. Чем короче окно — тем выше близость.

Код: Выделить всё

span(d, q) = min длина окна [i, j], содержащего все термины запроса
proximity_score ∝ 1 / (1 + span − |q|)      // span − |q| = «лишние» слова внутри окна
Если все термины стоят подряд, span = |q|, «лишних» слов 0, бонус максимален.
Пример. Запрос {кофе, доставка}. Текст: «… свежий кофе с быстрой доставкой …». Позиции: кофе=10, доставка=13. Минимальное окно [10,13] длиной 4, лишних слов 4 − 2 = 2. Бонус ∝ 1/3. В другом документе «кофе доставка» подряд: окно длиной 2, лишних 0, бонус ∝ 1 — втрое выше.
(б) Сумма по парам (pairwise distance). Для каждой пары терминов запроса берём минимальное расстояние между их ближайшими вхождениями и агрегируем затухающей функцией:

Код: Выделить всё

prox(d,q) = Σ      f(mindist(ti, tj)),   где f(x) = 1/x²  или  exp(−x/σ)
          i<j
Функция f быстро затухает с расстоянием: соседние слова дают много, слова за 50 токенов — почти ноль.
Инженерная заметка. Один из практичных приёмов — встроить близость прямо в BM25-подобную формулу через «псевдо-tf пар»: рядом стоящая пара терминов трактуется как дополнительное «вхождение» виртуального би-граммного термина, к которому применяется то же насыщение. Это даёт сигнал близости в той же шкале, что и основной скор, и легко комбинируется.
Порядок и фразовость
Интуиция. «Ремонт квартир» и «квартир ремонт» — близки по смыслу, но для многих запросов порядок несёт смысл («стол для кухни» ≠ «кухня для стола»). Точная фраза — самый сильный текстовый сигнал соответствия.
Иерархия силы текстового совпадения (от слабого к сильному):

Код: Выделить всё

Уровень       |  Что совпало                     |  Сигнал
--------------+----------------------------------+------------------------
Разрозненно   |  термины есть, но далеко         |  базовый BM25
Кучно         |  термины в одном окне            |  + proximity
По порядку    |  термины идут в порядке запроса  |  + ordered-proximity
Точная фраза  |  термины подряд, как в запросе   |  + phrase match (макс.)
Проверка фразы делается по позиционному индексу: термины фразы должны иметь позиции p, p+1, p+2, … подряд в одном документе. Алгоритмически — пересечение позиционных списков со сдвигом:

Код: Выделить всё

phrase(t1 t2 t3) встречается, если ∃ p:
   p   ∈ positions(t1, d)
   p+1 ∈ positions(t2, d)
   p+2 ∈ positions(t3, d)
Порядок без строгой смежности (ordered span): то же минимальное окно, но с требованием, что термины внутри окна идут в порядке запроса; за нарушение порядка — меньший бонус, чем за точную фразу, но больший, чем за хаотичное окно.
Заметка о стоп-словах и стемминге. Перед проверкой фразы текст проходит ту же нормализацию, что и запрос (Модуль 5): стемминг/лемматизация и, возможно, удаление стоп-слов. Поэтому «ремонт квартир» и «ремонта квартиры» обычно матчатся как фраза. С удалением стоп-слов аккуратнее: «группа крови» без стоп-слов может схлопнуться, поэтому стоп-слова в фразах часто сохраняют как «дырки» в позиционной проверке.
Инженерная заметка (стоимость). Proximity и фразы дороже BM25: нужны позиционные списки (тяжелее по памяти и I/O) и попарная/оконная обработка позиций. Поэтому их почти никогда не считают на всём корпусе. Типичная схема каскада (Модуль 12): L0 быстро отбирает кандидатов по AND/BM25 без позиций → L1 досчитывает proximity/phrase только для top-K кандидатов → L2+ подаёт это как признаки в обучаемую модель. Позиционные данные читаются лениво только для выживших документов.
Как это собирается в общий текстовый скор

На практике proximity/phrase редко используют как единственный балл — это набор признаков, подаваемых в модель ранжирования (Модуль 9):
  • bm25_body, bm25_title, …
  • coverage (доля найденных терминов),
  • min_span, ordered_span,
  • exact_phrase_hits (число точных вхождений фразы запроса),
  • pairwise_proximity.
Линейная (или обучаемая) комбинация этих сигналов почти всегда обыгрывает чистый BM25 на «многословных» запросах.

Частые заблуждения
Заблуждение. «BM25 уже учитывает, что слова рядом.» Нет: BM25 — мешок слов, он видит только частоты, но не позиции. Близость и фразы — отдельные сигналы поверх позиционного индекса.
Заблуждение. «Точная фраза в запросе означает, что система ищет только точное совпадение строки.» В современном поиске даже фразовые совпадения проходят через нормализацию (стемминг, синонимы); «точная фраза» — это сильный бонус, а не обязательно жёсткий строковый фильтр (кроме явного оператора кавычек).
Заблуждение. «Чем ближе слова, тем линейно лучше.» Близость, как и частота, насыщается: соседство даёт большой бонус, но «ещё на один токен ближе» при и так малом расстоянии почти ничего не меняет; функция затухания обычно нелинейна.
Лаба / практика

Задача. Реализуйте позиционный индекс и три сигнала близости. Время ~50 мин.

Входные данные. 5 документов, каждый — список токенов с позициями. Запрос из 3 слов, присутствующий во всех документах с разной «кучностью» (в одном — точной фразой, в другом — вразброс).

Шаги.
  1. Постройте позиционный индекс: термин → {doc_id: [позиции]}.
  2. Реализуйте coverage(d, q).
  3. Реализуйте min_span(d, q) — минимальное окно, содержащее все термины (алгоритм: указатели по отсортированному слиянию позиций или скользящее окно). Верните длину окна.
  4. Реализуйте exact_phrase(d, q) через сдвиговое пересечение позиций; верните число вхождений фразы.
  5. Постройте итоговый учебный скор: 0.5·bm25_norm + 0.3·(1/(1+span−|q|)) + 0.2·phrase_hits и отранжируйте.
  6. Покажите документ, который при чистом BM25 был не первым, но поднялся в топ за счёт точной фразы.
Критерий «сделано». min_span корректно равен |q| для документа с фразой; exact_phrase находит фразу; итоговое ранжирование отличается от чистого BM25 в ожидаемую сторону; вы можете оценить, во сколько раз позиционная обработка дороже подсчёта tf.

Контрольные вопросы
  1. Чем покрытие запроса отличается от частоты термина и почему его выделяют в отдельный сигнал?
  2. Как устроен алгоритм минимального покрывающего окна и какова его сложность от числа вхождений?
  3. Почему функция близости обычно затухает нелинейно (например, 1/x²)?
  4. Как по позиционному индексу проверить точную фразу из 3 слов?
  5. Чем «совпадение по порядку» сильнее «совпадения в окне», но слабее «точной фразы»?
  6. Почему proximity/phrase обычно считают только на верхних K кандидатах, а не на всём корпусе?
  7. Как стемминг и стоп-слова влияют на проверку фразовости и какие тут подводные камни?
Глава 6.3. Зональная релевантность и веса полей (title/тело/URL/заголовки) (средний)

Цели обучения

После главы студент сможет:
  • Перечислить основные зоны (поля) документа и объяснить, почему их веса различаются.
  • Объяснить разницу между полем (field) и зоной (zone) и как они представлены в индексе.
  • Оценить, как зональные веса встраиваются в BM25F и в признаки LTR.
  • Понимать риски ручного назначения весов и почему их предпочтительно обучать.
Конспект

Документ структурирован: вхождение термина в title несёт больше сигнала о теме страницы, чем то же вхождение в навигационном меню или подвале. Зональная (полевая) релевантность — это учёт того, где в документе находится совпадение.

Какие бывают зоны и почему они весят по-разному

Код: Выделить всё

Зона                           |  Почему важна                                   |  Типичный относительный вес
-------------------------------+-------------------------------------------------+-----------------------------
title (заголовок страницы)     |  Автор кратко формулирует тему; виден в выдаче  |  очень высокий
URL / slug                     |  Структурный сигнал темы (/remont-kvartir/)     |  высокий, но осторожно
Заголовки H1–H3                |  Структура содержания, подтемы                  |  высокий
Основной текст (body)          |  Полное содержание                              |  базовый
Якорный текст входящих ссылок  |  Как документ описывают другие (Глава 6.4)      |  высокий, внешний
Мета-описание / alt            |  Вспомогательный текст                          |  низкий
Меню/подвал/реклама («хром»)   |  Шум, повторяется на всех страницах             |  минимальный или исключается
Интуиция. Зона — это «голос с разным авторитетом». title — сам автор, кратко и ответственно. Якорь — голос других сайтов (часто честнее автора). Подвал — повторяющийся шум, который почти ничего не говорит про конкретную страницу.
Поле vs зона
  • Поле (field) — отдельный логический атрибут с собственным словарём/постингами: title, body, url, anchors. Запросы могут адресоваться к полю (title:ремонт).
  • Зона (zone) — разметка участков внутри одного текстового потока (например, «этот фрагмент тела — заголовок H2»), хранится как диапазоны позиций.
Инженерная заметка. На практике комбинируют: индексируют несколько полей и внутри тела помечают зоны. В позиционном постинге к каждой позиции можно приписать флаг зоны/поля. При скоринге вес берётся по зоне вхождения. Это удваивает-утраивает размер постингов, поэтому зональность — компромисс между точностью сигнала и стоимостью индекса (Модуль 4).
Как зоны входят в скор

Вариант 1 — взвешенная сумма полевых скоров (наивный):

Код: Выделить всё

score(d,q) = Σ_f  w_f · BM25_f(d,q)
Простой, но страдает от двойного насыщения (см. критику в 6.1): одно вхождение в каждом из двух полей переоценивается.

Вариант 2 — BM25F (предпочтительный): взвешиваем частоты до насыщения (формула из 6.1). Это «правильная» зональная модель.

Вариант 3 — зоны как признаки LTR: каждому полю — свой признак (bm25_title, bm25_body, coverage_title, …), а веса обучает модель ранжирования (Модуль 9). Сегодня это доминирующий подход: ручные веса не успевают за разнообразием запросов.
Заблуждение. «Достаточно вынести веса полей в конфиг и подобрать руками.» Для пары полей — может быть. Но качество зависит от типа запроса (навигационный vs информационный), языка, вертикали — единый ручной набор весов почти всегда проигрывает обученному. Ручные веса хороши как базлайн и для интерпретируемости, не как финал.
Особый случай: URL и хлебные крошки

URL — слабый, но дешёвый и устойчивый к накрутке сигнал: термин в пути (/dostavka-cvetov/) подтверждает тему. Но: домен и общие сегменты (www, index, ru) шумят, а длинные «ключевые» URL легко набиваются спамерами. Поэтому вес URL умеренный, а сегменты часто токенизируют и чистят.
SEO-врезка. Практические следствия зональной модели:
- Title — самый недооценённый рычаг. Один точный заголовок, отражающий запрос пользователя, влияет сильнее, чем десяток повторов в теле. Не дублируйте title на всех страницах — уникальный title на страницу.
- H1/H2 структурируют тему — выносите подтемы в заголовки, это и сигнал, и польза для читателя.
- URL — слабый бонус, не повод городить /kupit-deshevo-bystro-nedorogo-remont-kvartir-moskva/: переспам в URL не усиливает, а похож на манипуляцию (Модуль 16).
- Подвал/меню почти не считаются — ключевые слова в подвале на всех страницах не дают зонального веса (это «хром», шум).
- Манипуляция весом полей (скрытый title-spam, набивка alt) — классический объект антиспама. Сильные зоны = сильный соблазн накрутки = пристальный надзор фильтров.
Частые заблуждения
Заблуждение. «Если поднять вес title, всегда станет лучше.» Слишком высокий вес title ломает информационные запросы, где ответ в теле, и поощряет title-спам. Веса — это баланс, который надо измерять (Модуль 19), а не «крутить вверх».
Заблуждение. «Ключевые слова в подвале и меню помогают, они же на странице.» Повторяющийся на всех страницах «хром» обычно детектируется (шаблонные блоки) и почти не вносит зонального веса; иногда исключается из индексации тела вовсе.
Заблуждение. «BM25F и сумма BM25 по полям — одно и то же.» Нет: разница в том, где применяется насыщение (до или после суммирования по полям), и это меняет результат, особенно при вхождениях в нескольких зонах.
Лаба / практика

Задача. Сравните наивную сумму полевых BM25 с BM25F на документах со структурой. Время ~45 мин.

Входные данные. 5 документов с полями title, body, url. Запрос из 2 слов. Среди документов: (A) слово только в title; (B) слово 10 раз в body; (C) слово по разу в title и body.

Шаги.
  1. Проиндексируйте по полям; посчитайте tf по каждому полю, длины и avgdl по полю.
  2. Реализуйте наивный Σ w_f·BM25_f и BM25F (веса title:3, body:1, url:1).
  3. Сравните ранжирования двух методов; обратите внимание на документ C (вхождения в двух полях).
  4. Покажите эффект двойного насыщения: на какой позиции C в наивном методе и в BM25F?
  5. Поэкспериментируйте: при каком весе title документ A (только title) обходит документ B (10 раз в body)? Объясните в терминах насыщения.
Критерий «сделано». Показано численно, что наивный метод переоценивает документ с вхождениями в нескольких полях; BM25F ведёт себя устойчивее; найден порог веса title, объяснён через насыщение.

Контрольные вопросы
  1. Почему вхождение термина в title весит больше, чем в подвале страницы?
  2. В чём разница между «полем» и «зоной» с точки зрения индекса?
  3. Почему наивная взвешенная сумма полевых BM25 хуже BM25F?
  4. Почему вес URL держат умеренным, несмотря на то что URL — структурный сигнал?
  5. Почему ручную настройку весов полей предпочитают заменять обучаемыми весами (LTR)?
  6. Какие зоны документа чаще всего исключают из текстового скоринга и почему?
  7. Чем сильные зоны (title, anchor) опасны с точки зрения антиспама?
Глава 6.4. Якорный текст и тексты-источники как сигнал релевантности (средний)

Цели обучения

После главы студент сможет:
  • Объяснить, почему якорный текст входящих ссылок — особенно сильный текстовый сигнал.
  • Описать, как якоря агрегируются в виртуальное поле документа.
  • Перечислить тексты-источники помимо якоря (окружение ссылки, текст редиректов, заголовки-источники).
  • Объяснить уязвимость якорного сигнала к манипуляции и базовые защиты.
Конспект

До сих пор мы оценивали релевантность по тексту самого документа. Но мощнейший текстовый сигнал часто лежит снаружи: то, как документ описывают другие страницы, ссылаясь на него.

Якорный текст (anchor text)

Якорный текст — это видимый текст гиперссылки, ведущей на документ. Если сотни страниц ссылаются на некий ресурс словами «прогноз погоды», то почти наверняка документ про прогноз погоды — даже если на самой странице слова «прогноз погоды» написаны мелко или картинкой.
Интуиция. Якорь — это краудсорсинговое название документа, данное независимыми авторами. Автор страницы может хитрить с собственным title; сотни внешних авторов независимо — гораздо более честный коллективный голос о том, «про что эта страница».
Почему якорь так силён:
  1. Внешняя точка зрения — труднее накрутить в одиночку (нужны другие сайты).
  2. Краткость и точность — люди подписывают ссылки коротко и по делу, как мини-запросы.
  3. Покрытие «немого» контента — описывает документы, чей собственный текст беден (PDF, картинки, формы, главные страницы).
  4. Совпадение с языком запросов — якоря формулируются как пользователи формулируют запросы.
Агрегация якорей в виртуальное поле

Якорный текст принадлежит не самой странице, а множеству ссылающихся страниц. При индексации все якоря, ведущие на документ d, собираются в виртуальное поле anchors(d):

Код: Выделить всё

anchors(d) = мультимножество якорных фраз всех входящих ссылок на d
Это поле затем участвует в BM25F как ещё одна зона со своим весом и своей нормировкой. Но наивно складывать все якоря в одну «простыню» опасно: 10 000 ссылок со словом «казино» дали бы дикую частоту. Поэтому применяют поправки:
  • Дедупликация по источнику-сайту: тысячи ссылок с одного домена считают как один (или логарифмически затухающий) голос, а не как тысячи. Голоса агрегируют по уникальным доменам/хостам, а не по страницам.
  • Насыщение по якорной частоте: как и везде, tf якоря насыщается (та же логика BM25).
  • Взвешивание источника качеством/авторитетом: якорь с авторитетного домена весит больше (связь с Модулем 7 — ссылочный граф).
  • Ограничение длины якоря: сверхдлинные «якоря-абзацы» обрезают или штрафуют (часто это спам).
Инженерная заметка. Сбор якорей — отдельный офлайн-проход по графу ссылок (после краулинга, Модуль 2, и каноникализации, Модуль 3 — якорь приписывается каноническому URL цели). Это требует инвертировать граф (для каждого d — кто на него ссылается и каким текстом) и устойчивости к редиректам и дублям. Якорное поле часто крупное и обновляется отдельным циклом от тела документа.
Другие тексты-источники

Якорь — главный, но не единственный «внешний» текст о документе:

Код: Выделить всё

Источник                                                     |  Что это                                             |  Сигнал
-------------------------------------------------------------+------------------------------------------------------+--------------------------------------------------------
Якорный текст                                                |  текст ссылки на d                                   |  сильный, внешний
Окружение ссылки (link context)                              |  предложение/абзац вокруг ссылки                     |  дополняет якорь, особенно для общих якорей вроде «тут»
Текст при редиректе                                          |  старый URL/якоря, ведшие на перенаправленный адрес  |  переносится на цель
Заголовки и текст карточек-цитирований                       |  как документ упоминают без прямой ссылки            |  слабее, но полезно для «немых» документов
Текст из структурированных описаний (каталоги, справочники)  |  сторонние описания                                  |  вспомогательный
Заблуждение. «Якорь "нажмите здесь" бесполезен.» Сам якорь — да, но окружающий текст (link context) часто несёт тему: «полный прогноз погоды [нажмите здесь]». Системы учитывают контекст ссылки именно из-за обилия неинформативных якорей.
Манипуляция и защита

Якорь силён — значит, его атакуют. Координированная простановка ссылок с одинаковым коммерческим якорем («купить X дёшево») с тысяч помоечных сайтов — классический спам.

Базовые защиты (подробно — Модуль 16):
  • агрегация по доменам/владельцам, а не по ссылкам (массовая накрутка с фермы сайтов схлопывается в немного голосов);
  • учёт авторитета источника (Модуль 7): голос мусорного сайта почти ничего не весит;
  • аномалия распределения якорей: естественный профиль якорей разнообразен (бренд, URL, «тут», вариации), а у накрученного — неестественно однородный коммерческий якорь; резкая однородность — признак манипуляции;
  • временна́я аномалия: всплеск одинаковых якорей за короткий срок подозрителен.
SEO-врезка. Что из этого следует честному оптимизатору:
- Якорный текст важен — естественные ссылки с осмысленным якорем помогают, особенно для страниц с бедным собственным текстом.
- Не управляйте якорями искусственно. Покупка ссылок с одинаковым «денежным» якорем — самый детектируемый паттерн (однородность профиля + низкокачественные доноры). Это путь под фильтр (Модуль 16), а не в топ.
- Естественный профиль разнообразен — реальные люди ссылаются по-разному (бренд, URL, описательно). Однородность — красный флаг для антиспама.
- Внутренние ссылки (со своего сайта) — тоже якоря: осмысленные анкоры внутренней перелинковки помогают индексации и тематизации, и они в вашей власти без риска.
- Помните про связь с Модулем 16: чем сильнее сигнал, тем строже фильтры на нём. Любая попытка «накрутить» сильный текстовый сигнал (title-spam, anchor-spam, набивка) — первый кандидат на санкции.
Частые заблуждения
Заблуждение. «Якорный текст — это часть текста самой страницы.» Нет: якорь принадлежит ссылающимся страницам и собирается в виртуальное поле цели при офлайн-обработке графа ссылок.
Заблуждение. «Больше ссылок с нужным якорем — линейно лучше.» Голоса агрегируют по доменам и насыщают; тысяча ссылок с одной фермы ≈ один слабый голос, а однородный коммерческий якорь скорее навредит.
Заблуждение. «Якорь работает, только если на странице нет нужных слов.» Якорь усиливает сигнал даже для богатых текстом страниц, но особенно ценен для «немых» документов (картинки, PDF, лендинги без текста).
Лаба / практика

Задача. Постройте виртуальное поле якорей и оцените влияние агрегации по доменам. Время ~45 мин.

Входные данные. Мини-граф: 8 страниц-источников (с указанием их домена и «авторитета» 0–1), каждая ссылается на одну из 3 целевых страниц с заданным якорным текстом. Запрос из 2 слов.

Шаги.
  1. Соберите для каждой цели anchors(target) = список (домен, авторитет, якорный_текст).
  2. Постройте две версии якорного tf: (a) наивную — считая каждую ссылку; (b) с дедупликацией по домену (один домен = один голос, например, максимум или лог-затухание).
  3. Посчитайте якорный BM25 для обеих версий и сравните ранжирование целей.
  4. Подмешайте «ферму»: 5 ссылок с одного мусорного домена (авторитет 0.05) с одинаковым коммерческим якорем на одну цель. Покажите, что наивная версия её незаслуженно поднимает, а версия с дедупликацией + взвешиванием авторитетом — нет.
  5. Включите якорное поле в BM25F тела+title и покажите, как «немой» документ (пустое тело, но хорошие якоря) попадает в топ.
Критерий «сделано». Наивная агрегация задрала цель с фермой; дедупликация по домену и вес авторитета это нейтрализовали; «немой» документ ранжируется по якорям; вы можете объяснить, почему агрегируют по доменам, а не по ссылкам.

Контрольные вопросы
  1. Почему якорный текст считается более «честным» сигналом темы, чем собственный title документа?
  2. Как и почему якоря агрегируют по доменам/владельцам, а не по отдельным ссылкам?
  3. Зачем учитывать окружение ссылки (link context), а не только сам якорь?
  4. Как якорный текст помогает ранжировать «немые» документы (PDF, изображения)?
  5. На каком этапе конвейера собирается якорное поле и при чём здесь каноникализация (Модуль 3)?
  6. Какие признаки выдают накрученный профиль якорей?
  7. Почему сила якорного сигнала автоматически означает усиленный надзор антиспама (Модуль 16)?
Итоги модуля
  1. Текстовая релевантность измеряет тему, а не качество — «о том ли документ», отдельно от авторитета, свежести и поведения.
  2. BM25 = редкость (IDF) × насыщенная частота × нормировка длины. Вклад частоты вогнут и ограничен — линейного выигрыша от повторов нет.
  3. k1 управляет насыщением, b — нормировкой длины. Их предельные случаи (k1→0, k1→∞, b=0, b=1) надо понимать наизусть.
  4. BM25F — правильная зональная модель: взвешивать частоты полей до единого насыщения, а не складывать готовые полевые скоры.
  5. Мешок слов недостаточен: покрытие запроса, близость (proximity), порядок и точная фраза — сильные дополнительные сигналы, требующие позиционного индекса.
  6. Зоны весят по-разному: title/H1/anchor — сильные, body — базовый, «хром» (меню/подвал) — шум; веса лучше обучать (LTR), чем крутить вручную.
  7. Якорный текст — внешний краудсорсинговый «голос» о теме, агрегируется в виртуальное поле по доменам с поправкой на авторитет.
  8. Чем сильнее текстовый сигнал, тем строже антиспам на нём — переспам, title-spam и anchor-spam детектируются и наказываются (Модуль 16).
Глоссарий модуля
  • Насыщение частоты (term frequency saturation) — вогнутое, ограниченное сверху преобразование tf, гасящее выгоду от множества повторов.
  • k1 — параметр BM25, задающий скорость насыщения частоты.
  • b — параметр BM25 нормировки на длину документа (0 — выкл, 1 — полная).
  • avgdl — средняя длина документа в корпусе, база нормировки длины.
  • IDF (inverse document frequency) — вес редкости термина; в BM25 выводится из вероятностной модели релевантности.
  • BM25F — расширение BM25 на документы с несколькими полями: частоты полей взвешиваются и нормируются до общего насыщения.
  • Зона / поле (zone / field) — структурный участок/атрибут документа (title, body, URL, заголовки) со своим весом в скоринге.
  • Покрытие запроса (query coverage) — доля уникальных терминов запроса, присутствующих в документе.
  • Близость (proximity) — мера взаимной близости терминов запроса в документе; считается по позиционному индексу.
  • Минимальное покрывающее окно (span) — кратчайший отрезок текста, содержащий все термины запроса.
  • Фразовое совпадение (phrase match) — наличие терминов запроса подряд в порядке запроса; сильнейший текстовый сигнал.
  • Якорный текст (anchor text) — видимый текст ссылки; собирается в виртуальное поле документа-цели.
  • Окружение ссылки (link context) — текст вокруг гиперссылки, дополняющий якорь.
Связи с другими модулями
  • Опирается на: Модуль 1 (булева/векторная модели, базовый tf-idf, понятие релевантности); Модуль 4 (обратный и позиционный индекс, постинги, поля/зоны, стоимость хранения позиций).
  • Использует результаты: Модуль 5 (понимание запроса: какие термины обязательны, синонимы, стемминг — влияет на покрытие и фразовость); Модуль 3 (каноникализация — куда приписывать якоря); Модуль 7 (ссылочный граф — авторитет источника якоря).
  • Питает дальше: Модуль 8 (текстовые сигналы как класс факторов); Модуль 9 (bm25_*, proximity, coverage, phrase — признаки LTR); Модуль 10 (нейропоиск часто комбинируется с BM25 как сильным базлайном/первым уровнем); Модуль 12 (где именно в каскаде L0–L2 считаются дешёвый BM25 и дорогие proximity/phrase).
  • Тесно связан: Модуль 16 (антиспам: переспам, title-spam, anchor-spam — обратная сторона сильных текстовых сигналов); Модуль 19 (как измерять и подбирать k1, b, веса полей); Модуль 20 (прикладное SEO).
Материалы для углубления
  • Классические работы по вероятностной модели релевантности и выводу BM25 (Probabilistic Relevance Framework, веса Робертсона–Спарк Джонс).
  • Обзоры по BM25F и зональному/полевому ранжированию структурированных документов.
  • Литература по моделям близости и фразовому поиску (минимальные покрывающие окна, term-dependence модели, марковские случайные поля для IR).
  • Исследования по якорному тексту как сигналу и его агрегации; работы об устойчивости текстовых сигналов к манипуляциям (мост к антиспаму).
  • Обзоры по настройке гиперпараметров ранжирования и оценке текстовой релевантности (мост к Модулю 19).
👍3 ❤️3 🔥2 😄 🤔2
Аватара пользователя
Scfreeman
Сообщения: 1
Зарегистрирован: 20 май 2026, 00:28

Re: Текстовая релевантность

Сообщение Scfreeman »

по BM25 вопрос - как у вас подбирались k1 и b? дефолтные 1.2 и 0.75 на нашей короткой документной базе давали перекос, пришлось крутить b почти к нулю потому что длина доков была примерно одинаковая
👍1 ❤️1 🔥 😄 🤔
Аватара пользователя
kluaykai99
Сообщения: 1
Зарегистрирован: 13 май 2026, 10:26

Re: Текстовая релевантность

Сообщение kluaykai99 »

ага, вот теперь понятно зачем нужна нормализация по длине документа. без нее длинные простыни тупо набирали вес за счет повторов терма, а BM25 через насыщение tf это гасит. классический tf-idf этим страдал
👍 ❤️2 🔥 😄 🤔
Аватара пользователя
blmoore
Сообщения: 1
Зарегистрирован: 12 май 2026, 14:43

Re: Текстовая релевантность

Сообщение blmoore »

дополню что чистый текстовый матч без поведения и ссылок отлично работает как первый этап отбора кандидатов. мы гоняем BM25 для retrieval топ-1000, а уже потом сверху накидываем ml-реранкинг. дешево и сердито
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Обработка и понимание запроса
Следующая глава →
Анализ ссылочного графа

Все главы курса «Поисковые системы: индексирование, факторы ранжирования и формирование выдачи»

Поделиться темой: ✈ Telegram VK

Вернуться в «Поисковые системы: индекс, факторы, выдача»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость