Алгоритмы BM25 и TF-IDF: математика текстовой релевантности документа
1. Архитектура и принцип работы
TF-IDF считает вес слова как tf * idf, где tf — частота в документе, idf — логарифм отношения общего числа документов к числу документов с этим словом. BM25 улучшает формулу: вес термина = idf * (tf * (k1+1)) / (tf + k1 * (1 - b + b * dl/avgdl)). Здесь k1 управляет насыщением частоты (обычно 1.2–2.0), b — степень нормализации длины (0.75), dl — длина документа, avgdl — средняя длина по корпусу. BM25 штрафует длинные документы и не позволяет одному слову доминировать при повторах. Обе метрики требуют предварительной токенизации, лемматизации и удаления стоп-слов. В AI-контенте их применяют для проверки плотности ключевых слов и подбора синонимов: если вес LSI-термина ниже ожидаемого, модель добавляет его в текст.
2. Математическая механика и триггеры ранжирования
Классический TF-IDF: tf(t,d) = count(t,d) / |d|, idf(t) = log(N / df(t)), вес = tf * idf. BM25: score(D,Q) = Σ idf(qi) * (f(qi,D) * (k1+1)) / (f(qi,D) + k1 * (1 - b + b * |D|/avgdl)), где idf(qi) = log((N - df(qi) + 0.5)/(df(qi) + 0.5) + 1). Параметры k1=1.2–2.0, b=0.75. Для русского языка важна лемматизация (pymorphy2) или стемминг. BM25 насыщает частоту: при f >> k1 вес выходит на плато idf*(k1+1). Нормализация длины через b снижает вес длинных документов. В поиске BM25 применяется к инвертированному индексу, а TF-IDF — для быстрой фильтрации. Для AI-контента считают косинусную близость TF-IDF векторов к эталонному LSI-профилю.
3. Специфика в Яндекс (YATI) vs Google
Google исторически использует BM25 как базовый сигнал, но с 2015 года добавляет нейросетевые модели (RankBrain, BERT) для понимания контекста. Яндекс применяет BM25 в сочетании с матрикснетом и региональными факторами, а также учитывает коммерческие и поведенческие сигналы. В обоих поисковиках чистый TF-IDF устарел: он не различает омонимы и порядок слов. Для SEO-контента важно, что Google сильнее штрафует переспам (высокий TF при низком IDF), а Яндекс чувствительнее к LSI-разнообразию и морфологии. BM25 в Яндексе часто настроен с меньшим b (0.5–0.7) для длинных текстов, чтобы не занижать вес статей. Обе системы используют IDF для отсева стоп-слов и общеупотребительной лексики.
4. Нормативы SLA и диагностическая матрица
| Параметр / Метрика | Эталон по SLA | Критическая ошибка |
|---|---|---|
| IDF ключевого слова | > 3.0 | < 1.5 |
| BM25-вес топ-слова (k1=1.5, b=0.75) | 0.6–1.0 от максимума | < 0.3 или > 1.5 (переспам) |
| Косинусная близость TF-IDF к эталону | 0.65–0.75 | < 0.5 или > 0.9 (копипаст) |
5. Пошаговый инженерный протокол внедрения
- Соберите корпус из 50–100 документов конкурентов по теме, лемматизируйте через pymorphy2 и посчитайте IDF для каждого LSI-слова — слова с IDF ниже 2.0 не несут тематической нагрузки.
- Для целевой страницы рассчитайте BM25-вес каждого ключа и сравните с медианой по корпусу: если вес ниже 25-го процентиля, добавьте термин в текст без переспама.
- Настройте k1=1.5 и b=0.75 для статей длиной 1000–2000 слов, проверьте, что топ-5 LSI-слов имеют вес не менее 0.6 от максимального.
- Прогоните готовый текст через скрипт косинусной близости TF-IDF к эталонному профилю — порог сходства 0.65–0.75, иначе перепишите введение и подзаголовки.
def bm25_weight(tf, dl, avgdl, idf, k1=1.5, b=0.75):
return idf * (tf * (k1 + 1)) / (tf + k1 * (1 - b + b * dl / avgdl))
# Пример: tf=5, dl=1200, avgdl=1000, idf=3.2
# weight = 3.2 * (5 * 2.5) / (5 + 1.5 * (1 - 0.75 + 0.75 * 1.2)) = 3.2 * 12.5 / (5 + 1.5 * 1.15) ≈ 3.2 * 12.5 / 6.725 ≈ 5.95
6. Типичные ошибки при оптимизации
- Использование сырых частот без лемматизации: формы «ключ», «ключа», «ключи» считаются разными терминами, IDF завышается, релевантность падает.
- Игнорирование нормализации длины: длинная статья с тем же числом вхождений получает неоправданно высокий TF-IDF, но BM25 её штрафует — дисбаланс метрик сбивает оценку.
- Переспам LSI-слов с низким IDF (общеупотребительных): они не повышают тематическую релевантность, но раздувают TF и могут вызвать фильтр за спам.
