Сборка SERP: host-collapsing, blender и потолок в 259 документов

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

Сборка SERP: host-collapsing, blender и потолок в 259 документов

Сообщение anna_seo »

Сборка SERP: как из тысяч кандидатов рождается одна страница выдачи

Разбор основан на утёкших исходниках поиска Яндекса, срез примерно 2022 года. Речь о двух стадиях: робот (краулинг и индексация) и search/ (рантайм формирования выдачи). Здесь нас интересует именно финальная стадия - то, что происходит между моментом, когда базовый поиск уже отобрал документы-кандидаты, и моментом, когда пользователь видит десять строк на странице. Имена компонентов, пути и пороги приведены как в источнике. Дисклеймер: за прошедшее время имена, константы и пороги могли смениться, веса любых факторов иллюстративны - реальные обучаемы и проприетарны.

Откуда берётся выдача: средний метапоиск и слияние

SERP не строится одним монолитом. Запрос проходит через метапоиск, который рассылает подзапросы источникам (шардам базового поиска) и собирает их ответы. Центральный класс - TMetaSearch.

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

TMetaSearch        meta/metasearch.h:153   рассылка по источникам (scatter)
scatter runner     meta/scatter/runner.h   собственно scatter-gather
TMergeContext      meta/merge.h:26         инкрементальное слияние
TIncrementalMerger meta/unionmerge.h       слияние группировок на лету
Ключевое слово - scatter: запрос разлетается по источникам, а TMergeContext::Merge() инкрементально (по мере поступления ответов) сливает не отдельные документы, а уже сформированные группировки. Результат слияния - двухуровневая структура, и это важно для всего дальнейшего:

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

TMetaGrouping   - вся группировка целиком
  TMetaGroup    - одна группа = один сайт/домен
    TMergedDoc  - конкретный документ внутри группы
(meta/mergedres.h)
То есть выдача внутри движка изначально устроена не как плоский список URL, а как список групп, где группа по умолчанию соответствует домену. Это фундамент host-collapsing.

Host-collapsing: почему с домена пускают не больше двух

Самое практически значимое ограничение для SEO живёт в группировке. Конфигурация - в TGroupingInfo.

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

TGroupingInfo (grouping/groupinfo.h:26)
  NumDocsInGroup   - сколько документов одного домена
                     допускается (типично 2 в топе)
  NumGroupsOnPage  - сколько групп на странице
  GetMaxDocsInGroup(groupIndex, mode)  (groupinfo.h:78)
Логика такая. Атрибут группировки по умолчанию - домен (обозначается d). Все документы одного домена попадают в одну TMetaGroup. NumDocsInGroup определяет, сколько документов из этой группы вообще имеют право показаться - типично два. NumGroupsOnPage задаёт, сколько разных групп (то есть разных доменов) помещается на страницу. При стандартных десяти результатах на странице это и даёт привычную картину: десять разных сайтов, изредка по два документа с одного.

Тонкость в методе GetMaxDocsInGroup(groupIndex, mode). Для головных групп - тех, что стоят выше всего, - в режиме GM_UNION допускается чуть больше документов, чем для остальных. Иначе говоря, лидеру выдачи иногда разрешают занять не два, а несколько мест подряд, тогда как всем прочим доменам - строго лимит. Это не баг, а сознательная асимметрия: сильному релевантному источнику дают развернуться в топе, а длинный хвост схлопывают жёстко.

Поверх группировки работает дедупликация по URL:

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

TMergeGroupingUrlDuplicatesFilter
   (web/util/grouping/grouping.h)
gKillDup - параметр агрессивности схлопывания
TMergeGroupingUrlDuplicatesFilter выкидывает URL-дубли внутри слитой группировки, а gKillDup регулирует, насколько агрессивно движок схлопывает близкие документы. Чем выше агрессивность, тем меньше шансов у второго-третьего URL с домена просочиться даже в пределах лимита группы.
Практический вывод первый: больше примерно двух URL с одного домена в топ не пускают. Это не штраф и не фильтр за переоптимизацию - это конструкция самой сборки выдачи. Группировка по домену включена по умолчанию, NumDocsInGroup типично равен 2, и обойти это контентом нельзя. Расчёт на захват топа десятью своими страницами по одному запросу несостоятелен: механически отрежет host-collapsing.
Blender: вставка вертикалей и состав страницы

После того как органика сгруппирована, в дело вступает blender - компонент, который собирает итоговую страницу из разных вертикалей (интентов): веб-документы, картинки, видео, новости, колдунщики.

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

TBlender (web/blender/blender/blender.h:103)
  CallRulesAfterBlenderFactors()
  CallRulesAfterBlend()
  SetDocPosition(url, pos, ..., TPlacement)
TBlender работает в два прохода правил: CallRulesAfterBlenderFactors() отрабатывает после того, как посчитаны блендерные факторы, а CallRulesAfterBlend() - после собственно смешивания. Метод SetDocPosition фиксирует, какой URL встаёт на какую позицию, с указанием TPlacement (размещения).

Решение о том, какие вертикали и куда вставлять, принимает отдельный резолвер:

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

TSerpResolver (web/blender/serp_resolver/serp_resolver.h)
режимы:
  ALLOW_ALL             - разрешить все интенты
  ALLOW_ONLY            - только перечисленные
  ALLOW_EXCEPT          - все, кроме перечисленных
  EXCLUSIVE_INSERT_MODE - эксклюзивная вставка
TSerpResolver решает, например, что под коммерческий запрос уместны картинки на третьей позиции, а под новостной - новостной блок наверху, и в каком именно режиме это делать. Режимы ALLOW_ONLY и ALLOW_EXCEPT - это белый и чёрный списки интентов для конкретного запроса, а EXCLUSIVE_INSERT_MODE отдаёт позицию вертикали монопольно.

Поскольку один и тот же сайт может попасть и в органику, и в картиночную или видеовертикаль, нужна сквозная дедупликация:

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

duplicate_cleaner
  THostDuplicateChecker     - дубли по хосту между вертикалями
  TServiceDuplicateChecker  - дубли по сервису
Дедуп между вертикалями не даёт одному домену показаться дважды - один раз в вебе и второй раз внутри вставленного колдунщика или видеоблока. Это расширение host-collapsing на межвертикальный уровень: лимит на присутствие домена считается по странице в целом, а не отдельно по каждой вертикали.

Факторы самого блендера считаются изолированно от веб-факторов:

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

web/rearrange/apply_blender/
  blender_web_features/
  blender_meta_features/
  blender_dssm_features/
То есть у решения о вставке вертикали свой набор признаков (web, meta и dssm-эмбеддинговые), отдельный от факторов ранжирования органики. Колдунщик конкурирует за позицию не теми же сигналами, что обычная ссылка.

Размер выдачи: потолок в 259 документов

Самое жёсткое ограничение задаётся константами размера выдачи. Они подтверждены прямо в исходнике.

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

adjust_serp_size/smart_adjust_serp_size.h:6-8
  DefaultPageSize = 10   - документов на странице
  MaxLastPage     = 24   - номер последней страницы
  DefaultMaxDocs  = 259  - максимум документов всего
Расшифровка простая. Стандартная страница - десять документов. Последняя достижимая страница имеет номер 24. И поверх этого жёсткий потолок: глубже 259 документов выдача физически не строится. Двадцать четыре страницы по десять дали бы 240, но реальный предел чуть выше из-за вставленных вертикалей и неравномерного размера страниц ближе к концу - отсюда и число 259, а не круглые 240.
Практический вывод второй: позиции за порогом примерно 259 документов недостижимы в принципе. Это не вопрос слабой релевантности - движок не материализует выдачу глубже этого предела. Любые рассуждения про "мы на 280-й позиции" бессмысленны: такой позиции не существует. Имеет смысл бороться только в пределах первых двух-двух с половиной сотен результатов, а реально - в пределах первых страниц, где работают host-collapsing и blender.
Финальная сериализация

Собранная и обрезанная выдача уходит на формирование ответа:

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

TTmplDataReport (report/templates_json/response.h)
  -> protobuf TReport / TGrouping / TGroup / TDocument
     (idl/meta.proto:40)
  -> JSON через TAppReportJsonPageCallback::Report()
Обратите внимание: двухуровневая структура группа-документ доезжает до самого ответа - в protobuf-схеме это TGrouping, TGroup, TDocument. То есть домен как единица группировки - не временная деталь рантайма, а часть контракта выдачи вплоть до JSON.

Сводка для практики
  • Выдача строится как группы по домену, а не как плоский список. NumDocsInGroup типично равен 2 - больше примерно двух URL с домена в топ не попадает, и контентом это не обходится.
  • Головным группам в режиме GM_UNION иногда дают чуть больше мест - асимметрия в пользу сильного лидера, не в пользу длинного хвоста.
  • gKillDup и TMergeGroupingUrlDuplicatesFilter дополнительно схлопывают близкие и дублирующиеся URL.
  • Blender через TSerpResolver вставляет вертикали и считает их собственными факторами; дедуп THostDuplicateChecker распространяет лимит на домен на всю страницу, включая вертикали.
  • Потолок DefaultMaxDocs равен 259 - позиций за ним не существует.
Ещё раз дисклеймер: срез примерно 2022 года, конкретные имена классов, пути и числовые пороги могли измениться; любые веса факторов здесь иллюстративны, настоящие обучаемы и закрыты. Но архитектурный каркас - группировка по домену, лимит документов в группе, блендер вертикалей и жёсткий потолок размера выдачи - объясняет два устойчивых наблюдаемых факта рынка лучше любых гипотез про "санкции": максимум примерно два URL с домена в топе и физическая недостижимость позиций за двумя с половиной сотнями.
👍 ❤️ 🔥 😄 🤔
Ответить
Поделиться темой: ✈ Telegram VK

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

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

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