Базовый поиск L0/L1: отбор кандидатов, panther и pruning против SEO

Рейтинг: 0% · 0 голосов
Разбор устройства поиска и факторов ранжирования: реконструкция формулы, поведенческие, текстовые, ссылочные и хостовые факторы, антиспам, что живо и что давно мёртво. Аналитика на основе метаданных факторов web_production.
Ответить
Аватара пользователя
anna_seo
Сообщения: 58
Зарегистрирован: 11 май 2026, 05:31

Базовый поиск L0/L1: отбор кандидатов, panther и pruning против SEO

Сообщение anna_seo »

Базовый поиск L0/L1: где робот встречает запрос

Базовый поиск - это первый из вычислительных рубежей выдачи. Он не ранжирует "красиво", его задача проще и грубее: из миллионов документов шарда за миллисекунды отобрать несколько сотен кандидатов, которые вообще имеет смысл показывать вышестоящим уровням (L2/L3 с тяжёлыми моделями). Именно здесь читается всё, что робот заранее записал в индекс: текст, аннотации, ссылочные сигналы, нейро-эмбеддинги документа. Для SEO это означает буквальное: на L0/L1 не оценивается ваш "контент-маркетинг", оценивается то, что краулер успел проиндексировать и упаковать в индекс. Если робот этого не записал - этого на отборе не существует.
Базовый поиск - это шов, где сходятся две половины системы: робот, который писал ERF/keyinv при индексации, и рантайм, который читает их как FI_-факторы при скоринге. Всё, что вы оптимизируете "для выдачи", сначала должно дожить до записи в этот индекс.
Дисклеймер: всё ниже - реконструкция по утёкшему срезу примерно 2022 года. Имена компонентов, слотов факторов и пороги могли смениться. Все веса в формулах иллюстративны - реальные обучаемы и проприетарны.

Демоны и точка входа

Базовый поиск разнесён на отдельные демоны-хранилища, каждый со своим main.cpp:

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

search/base_search/daemons/embedding_storage/main.cpp       нейро-эмбеддинги
search/base_search/daemons/inverted_index_storage/main.cpp  обратный индекс (hits)
search/base_search/daemons/keyinv/main.cpp                  робото-статика (текст/ann)
Главный эндпоинт отбора - метод TEmbeddingStorage::Reply() (base_search/embedding_storage/embedding_storage.h:59). Несмотря на имя "embedding storage", именно он оркестрирует весь конвейер кандидатов, потому что нейро-часть (DSSM) и текстовая часть в итоге сшиваются в один поток на L1.

Конвейер отбора: от запроса к кандидатам

Поток от входящего запроса до батча на MatrixNet выглядит так:

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

TTDecomposedRequest         panther/runtime/request/
   декомпозиция запроса на термины/n-граммы
        |
        v
TPantherSearcher            panther/runtime/searcher
   идёт по offroad-WAD обратному индексу
   отдаёт TMatchedDoc с text_hits
        |
        v
TInvertedIndexReader        base_search/inverted_index_storage/shard/
                            inverted_index_reader.h
   достаёт hits по хешам терминов
        |
        v
TL1DocsMerger              base_search/l1_filtering/l1_docs_merger.h
   сшивает кандидатов по DocId
   батчует по 64 документа
        |
        v
TL1RelevanceCalcer         base_search/l1_filtering/l1_relevance_calcer.h
   MatrixNet L1 на батч  ->  topN кандидатов
Ключевой момент - panther. Это компонент декомпозиции запроса: он разбирает запрос на слова, биграммы и n-граммы, и по offroad-WAD обратному индексу находит документы, где эти термины встречаются. На выходе - TMatchedDoc с text_hits, то есть позиции и веса совпадений. Дальше TInvertedIndexReader дочитывает по хешам терминов сами hits, а TL1DocsMerger сводит всё к единому списку кандидатов по DocId и режет его на батчи по 64 документа - именно такими порциями кормится MatrixNet L1.

Факторы L1: что считается прямо в рантайме

На базовом считается подмножество факторов - группа запросно-документных Q и часть текстовых T. Три семейства важны для понимания механики.

BM15 и покрытие запроса

Считаются в TPantherMatchFeaturesCalcer (base_search/l1_filtering/panther_match_features_calcer.h:132). BM15 - облегчённый родственник BM25 без нормировки на длину документа, что логично для дешёвого первого рубежа. Формула в первом приближении:

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

Bm15 += x * coeff / (coeff + 0.1)

  x      - реверс-вес слова (IDF-подобный вес термина)
  coeff  - сколько слов запроса реально покрыто

плюс отдельная фича WordCoverageAny - доля любого покрытия запроса
Смысл: редкое слово (большой реверс-вес x) при наличии покрытия даёт больший вклад, чем частотное. Покрытие запроса считается само по себе как отдельный сигнал. Никакой магии "плотности ключей" - это классический мешок терминов с весами.

TextMachine-фичи

Это шесть вариаций матча, каждая раскрывается в 4 фичи. Вариации - комбинация трёх осей:

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

ось 1: uni / bi / ngram        (униграммы, биграммы, n-граммы)
ось 2: с text-hits / без       (учитывать позиции совпадений или нет)
ось 3: с panther-весом / без   (взвешивать вкладом panther или нет)

каждая вариация раскрывается в 4 фичи:
  AnnotationMaxValueWeighted
  CosineMatchMaxPrediction
  Bm15
  WordCoverageAny
Все они заполняются в fill_new_l1_factors.cpp и кладутся в слоты FI_PANTHER_MATCH_*. То есть "релевантность текста запросу" на L1 - это не одно число, а матрица из совпадений на разных уровнях гранулярности (слово/пара/последовательность) с разными способами взвешивания. Для SEO это значит, что одиночное точное вхождение фразы - лишь одна ячейка этой матрицы, и переоптимизация под неё мало что меняет в остальных.

DSSM dot-product query-doc

Самое интересное. Поле TL1Doc.DssmDotProduct (base_search/l1_filtering/protos/l1_doc.proto:21) - это скалярное произведение эмбеддинга запроса на эмбеддинг документа. Документная сторона нейро не вычисляется в рантайме (это дорого), она заранее посчитана при индексации и хранится сжатой:

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

- эмбеддинг документа упакован в ui8 (один байт на компоненту)
- распаковка по compression_ranges при чтении
- источник записи - робот: bert / jupiter / library на этапе индексации
Это и есть "документная сторона" нейросети - тот самый DSSM-вектор, который робот посчитал по содержимому страницы и положил в индекс. На L1 он лишь распаковывается и умножается на вектор запроса. Вывод для оптимизатора прямой: семантику страницы оценивает модель на стороне робота при индексации, а не рантайм. Влиять на DssmDotProduct можно только через содержимое, которое увидел краулер.

Чтение робото-статики: keyinv

Демон keyinv загружает на базовый именно те lump-ы, которые в схеме робота числились как "выход индексации" (base_search/keyinv/index_loader.h):

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

keyinv.global.*.wad     (Text)            - текстовый индекс
ann.global.*.wad        (DSSM-аннотации)  - нейро-аннотации
linkann.global.*.wad                      - ссылочные аннотации (анкоры)
factorann.global.*.wad                    - факторные аннотации
Это ровно ann / factorann / linkann, которые на стороне робота были помечены как результат краулинга и обработки. Здесь они читаются при скоринге. Так замыкается шов: робот пишет ERF и keyinv при индексации - базовый читает их как FI_-факторы при отборе. linkann здесь особенно показателен: ссылочные анкоры участвуют в текстовом матче кандидата уже на первом рубеже, а не где-то на финальном ранжировании.

Pruning: статика качества режет ещё до L2

Pruning - это анти-SEO механизм самого нижнего уровня. В pruning/pruning_data.h структура TPruningData хранит предвычисленный статический ранг документа:

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

TPruningData
  - статический ранг по докам, тип ui16 (0..65535)
  - используется для обрезки списка кандидатов

StaticCalculate():
  Rank += 100   для навигационных документов
Статический ранг - это качество документа, не зависящее от запроса (аналог host-rank / query-independent quality). Кандидаты с низким статическим рангом отсекаются ещё до того, как их увидит L2 с тяжёлыми моделями. А навигационным документам ранг повышается на +100, что на шкале ui16 - заметный буст, гарантирующий им проход через рубеж.
Pruning - первое место, где статика качества буквально режет выдачу. Документ с богатым текстовым матчем, но низким статическим рангом может не дожить до L2 - его обрежут на L1 как кандидата. Это объясняет, почему "идеально оптимизированная под запрос" страница на слабом хосте не ранжируется: до фазы, где её релевантность могли бы оценить детально, она просто не доходит.
Итог для SEO
  • Базовый поиск - первый рубеж отбора. Тут читается то, что записал робот: текст (keyinv), нейро (ann/DssmDotProduct), ссылки (linkann), факторы (factorann).
  • Текстовая релевантность на L1 - это матрица: BM15, покрытие и шесть TextMachine-вариаций в слотах FI_PANTHER_MATCH_*. Одиночное вхождение фразы влияет лишь на часть ячеек.
  • Семантика документа (DSSM) считается на стороне робота при индексации и лишь читается в рантайме. Влиять на неё можно только содержимым, доступным краулеру.
  • Pruning по статическому рангу режет кандидатов до L2. Качество хоста и навигационность важнее, чем кажется, потому что работают раньше всего остального.
Дисклеймер повторно: срез примерно 2022, имена слотов, пороги (включая +100 и coeff 0.1) и формулы могли смениться; веса иллюстративны, реальные обучаемы и проприетарны.
👍 ❤️ 🔥 😄 🤔
Ответить
Поделиться темой: ✈ Telegram VK

Вернуться в «SEO и факторы ранжирования»

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

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