Обзор модуляЧасть II · ~6 ч · Сложность: (средний) · Пререквизиты: Модуль 2
В Модуле 2 планировщик обхода скачал из веба миллиарды HTTP-ответов. Но «ответ по URL» — это ещё не «документ». Один и тот же материал лежит под десятками адресов (http/https, www/без, со слэшем и без, с UTM-метками, через зеркала и CDN), а множество разных адресов отдают почти одинаковый текст (пагинация, версии для печати, агрегаторы, скопированные новости). Прежде чем индексатор (Модуль 4) построит обратный индекс, кто-то должен ответить на вопрос: что считать одним документом? Этим занимается каноникализатор — компонент офлайн-конвейера между обходом и индексацией.
Каноникализация решает три вложенные задачи. Первая — нормализация URL и выбор канонической формы адреса: из множества эквивалентных строк-URL выбрать одну представительную. Вторая — склейка зеркал хостов: когда два разных хоста отдают одно и то же, объединить их и выбрать главное зеркало. Третья — обнаружение near-duplicate: страницы с разными URL и даже разных хостов, но почти совпадающим содержимым, свести в кластеры и оставить в выдаче одного представителя. Поверх всего этого лежит четвёртая, объединяющая задача — группировка по владельцу (owner): какие хосты и домены принадлежат одному субъекту.
Главная мысль модуля: каноникализация определяет НОСИТЕЛЯ всех факторов. Все сигналы курса — авторитет по ссылкам (Модуль 7), поведенческие клики (Модуль 11), накопленная свежесть, репутация хоста и владельца (Модуль 16) — привязываются не к URL-строке, а к канонической единице. Если каноникализатор ошибся и развёл один документ на три дубля, то ссылки, клики и история тоже расщепляются на три части: каждая копия выглядит слабой, ни одна не набирает критической массы сигналов, и сильный документ проигрывает в ранжировании. Каноникализация — «нулевой фактор»: она не влияет на скоринг напрямую, но задаёт сущность, к которой все остальные факторы относятся.
После модуля вы будете уметь нормализовать URL без потери и без ложного склеивания смысла, проектировать процедуру выбора главного зеркала, реализовывать near-duplicate detection через шинглы, MinHash и SimHash с кластеризацией, а также понимать, как группировка по владельцу подпирает все последующие сигналы.
Как читать по трекам
- Студент CES — обязательно главы 3.1, 3.3 (вывод MinHash/SimHash — ядро модуля), 3.4. Глава 3.2 — на уровне принципа. Сделайте лабу по SimHash.
- Инженер — всё обязательно. Особое внимание: каноникализация как офлайн-стадия конвейера, потоковая дедупликация при обходе, выбор представителя кластера, влияние ошибок склейки на индекс и serving (связь с Модулями 4, 12).
- SEO — обязательно 3.1 (нормализация, rel=canonical), 3.2 (зеркала, склейка www/https), 3.4 (владелец и хостовые сигналы). Все SEO-врезки. Математику MinHash/SimHash в 3.3 — обзорно, но понимать вывод «дубль = размывание сигналов» строго обязательно.
- Смешанный — обзор модуля, главы 3.1 и 3.4 целиком, идея 3.3 без вывода формул.
- 3.1. Нормализация URL и выбор канонической формы — как из множества эквивалентных адресов выбрать один, не потеряв и не склеив смысл.
- 3.2. Зеркала хостов и выбор главного зеркала — обнаружение хостов с идентичным содержимым и выбор представителя.
- 3.3. Near-duplicate detection — шинглы, MinHash, SimHash, кластеризация почти-дублей.
- 3.4. Группировка по владельцу (owner) — «нулевой фактор», на котором держатся все остальные сигналы.
Цели обучения
После главы студент сможет:
- Объяснить, почему один документ имеет множество URL-представлений и чем это вредит поиску.
- Перечислить безопасные и небезопасные правила нормализации URL и обосновать различие.
- Реализовать процедуру нормализации URL, дающую стабильный ключ дедупликации.
- Объяснить роль директивы rel=canonical и её отношение к серверной нормализации.
- Оценить риски ложного склеивания и ложного разведения адресов.
URL — это адрес ответа, а не идентичность содержимого. Проблема в том, что синтаксически разные строки-URL сплошь и рядом указывают на один и тот же ресурс. Цель нормализации — привести эквивалентные URL к единой канонической форме (canonical form), чтобы дедупликация, фронтир обхода и привязка сигналов работали с одним ключом.
Источники множественности URLИнтуиция. Представьте, что у дома есть десяток записей адреса: «ул. Садовая, д. 5», «Садовая 5», «садовая, 5 (вход со двора)». Почтальон должен понимать, что это один дом, иначе разнесёт письма по разным «ящикам», и ни один не окажется полным. URL-нормализация — это приведение всех записей адреса к одной канонической строке.
Один документ порождает множество адресов из-за:
- Схемы и порта: http:// против https://, явный :80/:443.
- Хоста: www. против голого домена, разный регистр хоста (хост регистронезависим).
- Пути: завершающий слэш (/page vs /page/), регистр (на части серверов путь регистрозависим, на части — нет), index.html как индекс каталога, сегменты ./ и ../.
- Query-string: порядок параметров, дублирующиеся параметры, трекинговые метки (UTM, идентификаторы сессий, рефереры), параметры, не влияющие на контент.
- Фрагмента (#...): якорь внутри страницы, который сервер вообще не видит.
- Процентного кодирования: %2D против -, регистр hex-цифр, кодирование незарезервированных символов.
«Безопасные» правила определены так, что не меняют смысл ресурса по стандарту URI — их можно применять почти всегда:
Код: Выделить всё
Правило | Было | Стало
-----------------------------------------+------------------------+----------------------
Нижний регистр схемы и хоста | HTTP://Example.COM/A | http://example.com/A
Удалить порт по умолчанию | https://h:443/p | https://h/p
Декодировать незарезервированные октеты | /%7Euser | /~user
Привести регистр процент-кодов | /a%2fb | /a%2Fb
Убрать ./..-сегменты | /a/./b/../c | /a/c
Удалить фрагмент | /p#section | /p
Пустой путь → / | http://h | http://h/
Небезопасные (эвристические) правилаИнженерная заметка. Удаление фрагмента безопасно для серверной идентичности, но осторожно: на SPA-сайтах фрагмент после #! (исторический hashbang) или внутри JS-роутинга мог адресовать разный контент. В современном вебе это редкость, но каноникализатор должен иметь исключения для известных паттернов.
Эти правила меняют ключ дедупликации и могут ошибиться — применяются только при наличии подтверждающих сигналов:
- Завершающий слэш. /page и /page/ обычно одно и то же, но формально это разные ресурсы. Решение принимают по факту: одинаковый ли ответ, есть ли редирект одного на другой.
- www vs голый домен — на самом деле задача склейки зеркал (глава 3.2), а не чистой нормализации.
- Удаление параметров. Трекинговые метки (utm_*, sessionid, fbclid-подобные) почти всегда не влияют на контент — их режут. Но параметр ?id=42 или ?page=2 контент-определяющий, и его резать нельзя.
- Сортировка параметров. ?a=1&b=2 и ?b=2&a=1 обычно эквивалентны, но не на всех бэкендах.
Канонический ключ и редиректыВнимание. Граница «контент-определяющий vs незначимый параметр» — главный источник ошибок. Слишком агрессивная резка склеит разные товары в один; слишком осторожная — разведёт один документ на тысячи URL по сессиям. На практике классификацию параметров ведут per-host: каноникализатор накапливает статистику «меняет ли этот параметр содержимое» по реально скачанным ответам.
Результат нормализации — канонический ключ (стабильная строка или её хеш), под которым документ живёт во всём конвейере. Помогают подтверждающие сигналы:
- HTTP-редиректы (301/308 постоянные, 302/307 временные): если A устойчиво ведёт на B, то B — кандидат в канонические, а сигналы A наследуются B.
- Идентичность тела ответа: два URL вернули байт-в-байт (или почти, см. 3.3) одинаковое — повод склеить.
- Декларация rel=canonical в HTML-разметке: сайт сам подсказывает предпочтительный адрес.
Код: Выделить всё
Множество сырых URL Каноникализатор Канонический ключ
http://Example.com/p?utm=x#top ┐
https://example.com/p/ ┼──► нормализация + редиректы ──► https://example.com/p
HTTPS://EXAMPLE.COM:443/p ┘ + rel=canonical + сигналы
SEO-врезка. rel=canonical — это подсказка, а не приказ. Каноникализатор учитывает её как один сигнал наряду с редиректами, картой сайта, внутренней перелинковкой и идентичностью контента. Если вы указали rel=canonical на одну страницу, но ссылаетесь и редиректите на другую, поисковая система выберет ту, в которую «верит» совокупность сигналов. Правила гигиены: канонический URL — абсолютный и самореферентный (страница указывает каноником саму себя), он отдаёт 200, а не редирект/404, и совпадает с тем, что в карте сайта и во внутренних ссылках. Чем меньше противоречий между сигналами, тем предсказуемее склейка.
Частые заблужденияSEO-врезка. Параметры-метки (utm_*, идентификаторы кампаний) для каноникализатора — шум. Полагаться на то, что они «разведут» страницы, нельзя: их режут. И наоборот — если важные варианты товара различаются только параметром, который похож на трекинговый, их рискуют ошибочно склеить. Делайте контент-определяющие параметры явно «непохожими на метки» (?color=red, а не ?c=1) и при необходимости отдавайте отдельные канонические URL без меток.
Заблуждение. «Достаточно сравнивать URL как строки — одинаковые строки = один документ.» Наоборот: строковое равенство ловит лишь часть случаев. http://h/a и https://h/a/ — разные строки, но один документ; ?page=1 и ?page=2 — почти одинаковые строки, но разные документы. Нужна нормализация по смыслу, а не по символам.
Лаба / практикаЗаблуждение. «rel=canonical гарантированно склеит мои страницы так, как я написал.» Это сигнал-подсказка. При противоречии с редиректами, контентом и перелинковкой система выберет по совокупности, а не по одной директиве.
Нормализатор URL и ключ дедупликации. Дан список из ~30 сырых URL (включает регистр хоста, порты по умолчанию, #-фрагменты, utm_*, перестановку параметров, .//../, index.html).
Шаги:
- Реализуйте функцию normalize(url) со всеми безопасными правилами из таблицы.
- Добавьте резку списка известных трекинговых параметров и сортировку оставшихся.
- Сгруппируйте входные URL по полученному ключу; выведите кластеры.
- Найдите пару, которую ваша эвристика склеила ошибочно (например, по слишком широкой резке параметра), и опишите, какой подтверждающий сигнал (редирект/идентичность тела) предотвратил бы ошибку.
Код: Выделить всё
def normalize(u):
p = parse(u)
p.scheme = p.scheme.lower()
p.host = p.host.lower()
p = drop_default_port(p)
p.path = remove_dot_segments(p.path) or "/"
p.fragment = ""
q = [(k, v) for k, v in p.query if k not in TRACKING_PARAMS]
p.query = sorted(q)
return rebuild(p)
Контрольные вопросы
- Почему регистр хоста можно приводить к нижнему, а регистр пути — нет?
- Какие правила нормализации называются «безопасными» и в каком смысле?
- Чем отличается резка utm_source от резки ?page? Как каноникализатор различает их на практике?
- Почему фрагмент #... обычно удаляют и в каком случае это опасно?
- Является ли rel=canonical обязательной для исполнения? Что перевесит её при конфликте сигналов?
- Чем грозит слишком агрессивная и слишком осторожная резка query-параметров?
- Как редиректы 301 участвуют в выборе канонической формы и наследовании сигналов?
Цели обучения
После главы студент сможет:
- Дать определение зеркала (mirror) и отличить его от near-duplicate отдельных страниц.
- Объяснить, почему зеркала нужно склеивать на уровне хоста, а не каждой страницы по отдельности.
- Перечислить сигналы обнаружения зеркал и факторы выбора главного зеркала.
- Описать, как склейка зеркал переносит сигналы (ссылки, авторитет) на представителя.
Зеркало (mirror) — хост, отдающий то же содержимое, что и другой хост, с согласованной структурой URL. Классические случаи: www.site и site; http-версия и https-версия; региональные алиасы (site.example ↔ example); CDN-домены; отдельный домен «для печати» или мобильная версия; полностью скопированный сайт под другим доменом.
Почему склейка на уровне хостаИнтуиция. Если глава 3.1 решала «какая из строк-адресов одного дома правильная», то 3.2 решает «у этих двух разных зданий одинаковая планировка всех квартир — это один жилой комплекс или два?» Когда оказывается, что один — точная копия другого, мы объявляем один из них главным зданием, и вся почта (сигналы) идёт туда.
Можно было бы детектить дубли постранично (это глава 3.3), но для зеркал это расточительно и неточно. Если www.site/p ≡ site/p для тысяч страниц, выгоднее установить хостовое отображение www.site → site один раз и применять его ко всем путям. Это:
- экономит ресурсы обхода (не качаем оба зеркала целиком);
- даёт стабильную склейку даже для страниц, которые поодиночке выглядят непохоже;
- позволяет переносить хостовые сигналы (репутация, история, авторитет домена) на одного носителя.
Сигналы, что два хоста — зеркала:
- Совпадение содержимого по выборке путей. Берём набор путей, существующих на обоих хостах, сравниваем тела (через near-duplicate из 3.3). Высокая доля совпадений → зеркала.
- Структурная согласованность URL. Один и тот же путь /a/b/c есть на обоих и отдаёт одно и то же.
- Редиректы между хостами. Если http://h устойчиво 301→ https://h, или site → www.site, это прямое объявление главного зеркала самим сайтом.
- DNS/сетевые признаки (один IP, общий сертификат, охватывающий оба имени) — слабые вспомогательные сигналы.
- Совпадение карты сайта и внутренней перелинковки.
Выбор главного зеркалаИнженерная заметка. Зеркала проверяют по выборке путей, а не целиком: качать оба хоста полностью только ради проверки гипотезы — дорого. Берут несколько десятков общих путей, считают долю near-duplicate; при превышении порога склеивают хосты и далее обходят преимущественно главное зеркало, экономя бюджет обхода (политика вежливости и бюджет — Модуль 2).
Когда зеркала обнаружены, выбирают представителя (главное зеркало). Критерии, обычно по убыванию веса:
- Явная декларация сайта: куда ведут постоянные редиректы; что указано в rel=canonical; что в картах сайта.
- Безопасность и современность: https предпочтительнее http.
- Накопленный авторитет: на какой хост больше входящих ссылок, какая версия исторически известна (ссылочные сигналы — Модуль 7).
- Стабильность и доступность: какой хост надёжнее отвечает.
- Канонические соглашения: консистентность с тем, как сайт сам себя адресует (www или без).
Код: Выделить всё
www.site/article ┐
site/article ┼─► главное зеркало: https://site/article ◄─ сюда сходятся
http://site/article ┘ ссылки, клики, история
SEO-врезка. Не давайте поисковой системе угадывать главное зеркало — объявите его сами и согласованно. Практика: выберите один канонический хост (например, https://site без www), поставьте постоянный редирект 301 со всех остальных вариантов (http, www, лишние домены) на него, продублируйте выбор в rel=canonical, картах сайта и внутренних ссылках. Тогда весь ссылочный вес и история склеятся на одном носителе. Если же www и без-www версии независимо набирают ссылки и не склеены, авторитет домена расщепляется надвое — это прямой пример «размывания сигналов по дублям».
Частые заблужденияВнимание. Ошибочная склейка двух разных сайтов как зеркал (например, шаблонные сайты на одной CMS с почти идентичной обвязкой, но разным основным контентом) — серьёзная авария: контент одного исчезает из выдачи под представителем другого. Поэтому решающий сигнал — совпадение основного содержимого, а не общего каркаса (меню, футер, шаблон). Это мостик к главе 3.3: сравнивать надо значимый текст, отфильтровав бойлерплейт.
Заблуждение. «www.site и site — это очевидно один сайт, система разберётся сама.» Для машины это два разных хоста. Без редиректа или явных сигналов они могут жить как два носителя сигналов, деля между собой ссылки и историю.
Лаба / практикаЗаблуждение. «Чем больше зеркал/доменов с моим контентом, тем шире охват.» Наоборот: несклеенные копии конкурируют друг с другом и дробят сигналы; склеенные — отдают весь вес одному представителю, а лишние просто не показываются.
Детектор зеркал по выборке. Даны два хоста A и B и список из 20 общих путей с телами ответов (часть страниц совпадает, часть различается, на части — только общий шаблон).
Шаги:
- Для каждого общего пути посчитайте меру схожести тел (используйте Jaccard по шинглам из главы 3.3 — можно опереться на её лабу).
- Отфильтруйте бойлерплейт: удалите часто повторяющиеся между страницами блоки (меню/футер) перед сравнением.
- Посчитайте долю путей с схожестью выше порога; примите решение «зеркала / не зеркала».
- Если зеркала — выберите главное по правилам (есть редиректы? https? больше входящих ссылок — даны в условии).
- Покажите, как фильтрация бойлерплейта изменила решение по сравнению с наивным сравнением целых страниц.
Контрольные вопросы
- Чем зеркало отличается от near-duplicate отдельной страницы?
- Почему зеркала выгоднее склеивать на уровне хоста, а не каждой страницы?
- Какие сигналы говорят, что два хоста — зеркала? Какой из них самый надёжный?
- По каким критериям выбирают главное зеркало и почему https обычно предпочтительнее?
- Почему при сравнении хостов важно отфильтровать бойлерплейт?
- Что произойдёт с авторитетом домена, если www- и без-www-версии не склеены?
- Чем опасна ошибочная склейка двух разных сайтов как зеркал?
Цели обучения
После главы студент сможет:
- Сформулировать near-duplicate как задачу оценки схожести множеств/документов и выбрать меру (Jaccard, косинус, расстояние Хэмминга).
- Объяснить и реализовать шинглинг документа в множество k-грамм.
- Вывести, почему MinHash даёт несмещённую оценку Jaccard, и оценить число хешей для нужной точности.
- Объяснить SimHash как локально-чувствительный хеш и сравнить его с MinHash по применимости.
- Реализовать кластеризацию почти-дублей через LSH (бандлы MinHash или близость SimHash) и выбрать представителя кластера.
Near-duplicate — документы, почти, но не точно совпадающие по содержимому: новость, перепечатанная на сотне сайтов; товар с одинаковым описанием на разных страницах; версия «для печати»; страница, отличающаяся лишь датой и счётчиком. Точные дубли ловятся хешем всего тела (md5/sha). Сложность — именно «почти»: нужно мерить степень схожести и порогом решать, дубли ли это.
Шаг 1. Шинглинг (k-граммы)Интуиция. Две статьи — это два мешка слов/фраз. Если мешки пересекаются на 95%, это одна и та же статья с косметическими правками. Нам нужен дешёвый способ оценить «процент пересечения мешков», не сравнивая их попарно целиком — иначе на миллиардах документов это N² сравнений, невычислимо.
Представим документ как множество шинглов (shingles) — пересекающихся последовательностей из k подряд идущих токенов (слов). Для k=3 и текста «быстрая бурая лиса прыгнула» шинглы: {«быстрая бурая лиса», «бурая лиса прыгнула»}.
Шинглы из нескольких слов устойчивее к перестановкам и точнее, чем мешок отдельных слов: совпадение длинных фраз — сильный признак копии. Перед шинглингом текст нормализуют (нижний регистр, удаление пунктуации) и отрезают бойлерплейт (меню, футер, реклама), иначе шаблон сайта раздует мнимое сходство.
Мера схожести: JaccardИнженерная заметка. Чтобы не хранить длинные строки, каждый шингл хешируют в 64-битное число. Документ становится множеством 64-битных хешей. Выбор k: маленькое k (1–2) ловит даже слабо похожие тексты (много ложных склеек); большое k (5+) требует длинных дословных совпадений (пропускает перефразированные копии). На практике k≈3–5.
Схожесть двух множеств шинглов A и B:
Код: Выделить всё
J(A, B) = |A ∩ B| / |A ∪ B|
Шаг 2. MinHash — оценка Jaccard за дёшево
Идея: возьмём случайную хеш-функцию h, применим её ко всем элементам множества A и запомним минимум: minh(A) = min_{a∈A} h(a). Ключевая теорема:
Код: Выделить всё
P[ minh(A) = minh(B) ] = J(A, B)
Одно совпадение — шумная оценка (0 или 1). Берём m независимых хеш-функций, получаем сигнатуру из m минимумов. Доля совпавших позиций сигнатур — несмещённая оценка J:Интуиция вывода. Минимум хеша достигается на каком-то одном элементе объединения A ∪ B. Хеш «перемешивает» элементы случайно, так что любой элемент объединения равновероятно может оказаться минимальным. Этот элемент-минимум лежит и в A, и в B одновременно тогда и только тогда, когда он принадлежит пересечению A ∩ B. Вероятность этого = |A∩B| / |A∪B| = J. То есть «совпали ли минимумы» — это бросок монеты с вероятностью успеха ровно J.
Код: Выделить всё
Ĵ = (число совпавших позиций) / m
MinHash + LSH: кластеризация без N²Пример. Документ A → множество хешей шинглов. m=4 функции дают сигнатуру A=[12, 5, 71, 9], B=[12, 5, 71, 40]. Совпали 3 из 4 → Ĵ≈0.75. Истинный Jaccard оценивается в 0.75 без перебора пересечений множеств.
Сигнатуры есть, но сравнивать их попарно — снова N². Спасает Locality-Sensitive Hashing (LSH). Разбиваем сигнатуру из m минимумов на b бандов (bands) по r строк (m = b·r). Для каждого банда хешируем его r чисел в корзину. Кандидаты в дубли — документы, попавшие хотя бы в одну общую корзину хотя бы в одном банде.
Кандидатов (их немного) уже проверяют точнее и строят граф «дубль–дубль», затем выделяют связные компоненты или кластеризуют — это и есть кластеры near-duplicate.Интуиция. Если два документа очень похожи, у них совпадает много минимумов, и шанс, что целый банд совпадёт целиком, велик. Чем больше бандов — тем больше шансов «зацепиться». Параметры b и r задают S-образную кривую вероятности стать кандидатом от J: порог перегиба ≈ (1/b)^(1/r). Подбирая b, r, настраивают, при каком J пара почти наверняка попадёт в кандидаты.
Альтернатива: SimHash
SimHash — другой локально-чувствительный хеш, дающий документу одну битовую строку (например, 64 бита) так, что у похожих документов хеши различаются в малом числе бит (расстояние Хэмминга мало).
Алгоритм:
- Из документа извлекаем взвешенные признаки (шинглы/слова с весами, например по частоте).
- Каждый признак хешируем в 64-битный вектор.
- Заводим аккумулятор из 64 счётчиков. Для каждого признака: где бит хеша = 1, прибавляем вес; где 0 — вычитаем.
- Итог: бит результата = 1, если счётчик положительный, иначе 0.
Выбор представителя кластераСравнение MinHash vs SimHash.
| | MinHash | SimHash |
|---|---|---|
| Хранит | сигнатуру из m чисел | одно слово (напр. 64 бита) |
| Мера | Jaccard множеств | косинус/Хэмминг по взвешенным признакам |
| Память | больше | очень компактно |
| Точность оценки J | настраиваемая m | грубее, но дёшево |
| Поиск кандидатов | LSH-банды | поиск по малому Хэммингу (разбиение на блоки бит) |
MinHash удобен, когда нужна точная оценка Jaccard и гибкий порог; SimHash — когда документов очень много и важна компактность (одно 64-битное число на документ) и быстрый поиск «почти таких же».
В кластере near-duplicate в выдачу попадёт один представитель (остальные схлопнутся — Модуль 15). Критерии выбора первоисточника/представителя:
- Первичность во времени: кто опубликовал раньше (свежесть, Модуль 17).
- Авторитет носителя: хост/владелец с большим авторитетом (Модули 7, 3.4).
- Полнота и качество: более полная версия, без «для печати»-усечений.
- Поведенческие сигналы: на какую копию лучше реагируют пользователи (Модуль 11).
Частые заблужденияВнимание. Near-duplicate detection — это группировка для выбора представителя, а не удаление. Прочие копии остаются известны системе (например, как кандидаты в других интентах), но в основную выдачу по запросу попадает один представитель, чтобы не засорять топ повторами.
Заблуждение. «Хватит хеша всего тела — одинаковый хеш = дубль.** Это ловит только точные дубли. Изменение одного байта (дата, счётчик, порядок блоков) даёт совсем другой хеш, но документ — тот же. Нужны меры почти-схожести (Jaccard/Хэмминг), а не точное равенство.
Заблуждение. «MinHash и LSH дают точный ответ.» Они дают вероятностную оценку и кандидатов. Возможны ложные совпадения (разные документы в одной корзине) и пропуски (похожие не зацепились) — баланс настраивается параметрами m, b, r и финальной проверкой кандидатов.
Лаба / практикаЗаблуждение. «Сравнивать надо всю страницу целиком.» Общий шаблон сайта (меню, футер) раздувает сходство и склеивает разные документы. Перед шинглингом отделяют значимый контент от бойлерплейта.
SimHash-дедупликатор мини-корпуса. Дан корпус из ~12 коротких текстов: несколько точных дублей, несколько near-duplicate (правки/перестановки абзацев), несколько независимых.
Шаги:
- Нормализуйте текст, постройте шинглы k=3, взвесьте их частотой.
- Реализуйте 64-битный SimHash по алгоритму выше.
- Посчитайте попарные расстояния Хэмминга; постройте граф рёбер «≤3 бита».
- Выделите связные компоненты — это кластеры дублей.
- Для каждого кластера выберите представителя (по заданному в условии «времени публикации» и «авторитету»).
- Доп. Повторите оценку схожести через MinHash (m=100) и сравните, какие пары посчитались дублями обоими методами, а какие разошлись.
Код: Выделить всё
def simhash(features): # features: list[(token, weight)]
acc = [0]*64
for tok, w in features:
h = hash64(tok)
for i in range(64):
acc[i] += w if (h >> i) & 1 else -w
return sum((1 << i) for i in range(64) if acc[i] > 0)
def hamming(a, b):
return bin(a ^ b).count("1")
Контрольные вопросы
- Чем near-duplicate отличается от точного дубля и почему хеша тела недостаточно?
- Что такое шингл и как параметр k влияет на чувствительность к перефразированию?
- Сформулируйте и интуитивно обоснуйте равенство P[minh(A)=minh(B)] = J(A,B).
- Как число хешей m в MinHash связано с точностью оценки Jaccard?
- Зачем нужен LSH и как параметры b, r задают порог попадания в кандидаты?
- Чем SimHash отличается от MinHash по тому, что хранится и как ищутся кандидаты?
- Почему near-duplicate detection — это группировка с выбором представителя, а не удаление копий?
- По каким критериям выбирают представителя кластера дублей?
Цели обучения
После главы студент сможет:
- Дать определение владельца (owner) и отличить его от хоста и URL.
- Объяснить, почему владелец — «нулевой фактор», подпирающий ссылочные, поведенческие и репутационные сигналы.
- Перечислить сигналы для группировки хостов/доменов по владельцу.
- Оценить последствия ошибок группировки (и склейки, и разведения) для ранжирования и антиспама.
Иерархия идентичности в конвейере: URL ⊂ документ (после каноникализации) ⊂ хост ⊂ владелец (owner). Владелец — сущность (организация, лицо, проект), которой принадлежит группа хостов/доменов. Каноникализатор поднимает идентичность до этого верхнего уровня, потому что многие сигналы естественно живут именно на нём.
Почему владелец — «нулевой фактор»Интуиция. Документ — это квартира, хост — дом, владелец — управляющая компания, которой принадлежат несколько домов. Репутация управляющей компании переносится на все её дома: если одна УК известна махинациями, доверие к её новостройкам падает заранее. Так же поисковая система: накопив репутацию владельца, она применяет её ко всем его хостам.
Назовём это нулевым фактором, потому что он сам по себе не скорит документ, но определяет, к какой сущности относить все остальные сигналы. Без правильной группировки:
- Ссылочный авторитет (Модуль 7) размазывается. Сайт владельца с десятью доменами, ссылающимися друг на друга, без группировки выглядит как «десять независимых сайтов, голосующих друг за друга» — искусственно раздутый авторитет. С группировкой внутренние ссылки владельца обесцениваются (это самореклама), а внешние считаются честно.
- Поведенческие сигналы (Модуль 11) и репутация привязываются к хосту/владельцу. Если владелец дробит контент по доменам, история кликов и доверие не накапливаются ни на одном.
- Антиспам и пессимизация (Модуль 16) работают на уровне владельца: спамные сети из сотен доменов одного субъекта нужно видеть как единую сущность, иначе пессимизация одного домена бессмысленна — субъект поднимет новый.
- Схлопывание выдачи (Модуль 15) — нельзя занять весь топ десятком доменов одного владельца; ограничение применяется на уровне владельца, а не отдельного хоста.
Сигналы группировки по владельцуЭто центральный тезис всего модуля. Каноникализация и группировка определяют носителя факторов. Сначала near-duplicate и зеркала сводят копии к одному документу/хосту, затем группировка сводит хосты к владельцу. Только после этого ссылки, клики, свежесть и репутация «приземляются» на устойчивую сущность. Ошибка на любом уровне → сигналы размазываются по дублям/доменам, и сильная сущность выглядит как набор слабых.
- Регистрационные данные домена (общий регистрант/контакты, насколько доступны).
- Сетевые признаки: общий хостинг/IP-диапазон, общие сертификаты (слабые сами по себе — целые хостинги делят IP).
- Перелинковка и общая инфраструктура: систематические взаимные ссылки, общие счётчики/идентификаторы, шаблоны, единый раздел «о компании»/контакты.
- Контентные связи: перекрёстные канонические ссылки, единый бренд в разметке.
- Совпадение зеркал и редиректов (из глав 3.1–3.2): хосты, связанные редиректами, почти наверняка один владелец.
Код: Выделить всё
URL ──нормализация(3.1)──► документ
документ + зеркала(3.2) ──► хост (главное зеркало)
хост + near-dup(3.3) ───► канонический документ-представитель
хост ──группировка(3.4)─► ВЛАДЕЛЕЦ ◄── носитель: ссылки, клики, репутация, антиспам
SEO-врезка. Группировка по владельцу — причина, по которой «сетки сайтов» для накрутки ссылок не работают и опасны: система видит их как одного владельца, внутренние ссылки обесцениваются, а при срабатывании антиспама пессимизация бьёт по всей сети сразу. И наоборот: если вы дробите свой проект по множеству доменов без склейки, вы дробите и собственные сигналы — авторитет, история и поведенческие данные не накапливаются ни на одном носителе. Консолидируйте: один основной носитель, явные редиректы, согласованные каноникал-ссылки.
Частые заблужденияВнимание. Ошибка группировки опасна в обе стороны. Ложное объединение независимых сайтов на общем хостинге → невинный сайт наследует пессимизацию соседа. Ложное разведение одной спам-сети на «независимые» домены → антиспам неэффективен. Поэтому решающие сигналы — поведенческие и структурные (систематическая перелинковка, общая инфраструктура управления), а не только общий IP.
Заблуждение. «Владелец, хост и URL — про одно и то же.» Это вложенные уровни идентичности. Сигналы живут на разных уровнях: текстовая релевантность — на документе, авторитет и репутация — на хосте/владельце. Путать уровни — значит привязывать фактор не к тому носителю.
Заблуждение. «Заведу сто доменов и буду ссылаться сам на себя — авторитет вырастет.» Группировка по владельцу обесценивает внутренние ссылки сети и делает её мишенью для антиспама как единое целое.
Лаба / практикаЗаблуждение. «Общий IP/хостинг = один владелец.» Нет: дешёвый шаринг-хостинг держит тысячи независимых сайтов на одном IP. Это лишь слабый вспомогательный сигнал.
Группировка хостов по владельцу и эффект на сигналы. Дан мини-граф из 12 хостов: рёбра-ссылки, признаки (общий IP — да/нет, взаимные редиректы, общий идентификатор счётчика), плюс «истинная» разметка владельцев для проверки.
Шаги:
- Постройте оценку «один владелец» для пар хостов как взвешенную сумму сигналов (редирект — сильный, систематическая взаимная перелинковка — средний, общий IP — слабый).
- Кластеризуйте хосты в владельцев по порогу (связные компоненты по «сильным» рёбрам).
- Посчитайте суммарный ссылочный «вес» (упрощённо — число входящих ссылок) до и после обесценивания внутривладельческих ссылок.
- Покажите на конкретном кластере, как «сетка самоссылок» теряет искусственный авторитет после группировки.
- Найдите один случай, где наивная склейка по общему IP дала бы ложное объединение, и объясните, какой сигнал это предотвращает.
Контрольные вопросы
- Дайте определение владельца и расположите по вложенности: URL, хост, документ, владелец.
- Почему владельца называют «нулевым фактором»? Что значит «носитель сигналов»?
- Как ошибка группировки влияет на ссылочный авторитет и поведенческие сигналы?
- Почему «сетки сайтов» для накрутки не дают преимущества и чем опасны?
- Какие сигналы используют для группировки и почему общий IP — слабый?
- Опишите последствия ложного объединения и ложного разведения хостов.
- Как уровни идентичности (3.1→3.2→3.3→3.4) связаны в единый конвейер каноникализации?
- URL ≠ документ. Один материал живёт под множеством адресов; нормализация URL приводит эквивалентные адреса к единой канонической форме и даёт стабильный ключ дедупликации.
- Безопасные правила нормализации не меняют смысл по стандарту URI; эвристические (резка параметров, слэш) применяют только с подтверждающими сигналами — редиректами, идентичностью тела, rel=canonical.
- rel=canonical — подсказка, а не приказ; при конфликте решает совокупность сигналов (редиректы, контент, перелинковка, карта сайта).
- Зеркала склеивают на уровне хоста по совпадению значимого (не шаблонного) содержимого; главное зеркало выбирают по декларациям сайта, https, авторитету и стабильности.
- Near-duplicate меряют схожестью множеств/векторов: шинглинг → MinHash (несмещённая оценка Jaccard, P[совпадения минимумов]=J) или SimHash (компактный хеш, близость по Хэммингу) → LSH/связные компоненты → выбор представителя.
- MinHash vs SimHash: первый — точная настраиваемая оценка Jaccard через сигнатуры и банды; второй — компактное 64-битное представление и быстрый поиск «почти таких же».
- Группировка по владельцу — «нулевой фактор»: определяет носителя ссылочных, поведенческих, репутационных и антиспам-сигналов.
- Главный тезис: каноникализация определяет НОСИТЕЛЯ всех факторов. Без неё owner, хост, ссылки и поведение размазываются по дублям, и сильная сущность выглядит как набор слабых.
Код: Выделить всё
Термин | Англ. | Определение
------------------------+------------------------------+----------------------------------------------------------------------------
Каноническая форма URL | canonical URL form | Единая представительная строка-адрес для множества эквивалентных URL
Нормализация URL | URL normalization | Приведение URL к канонической форме по безопасным и эвристическим правилам
Канонический ключ | canonical key | Стабильный идентификатор документа во всём конвейере после каноникализации
Безопасное правило | safe rule | Преобразование URL, не меняющее ресурс по стандарту URI
rel=canonical | rel canonical | HTML-подсказка о предпочтительном URL; сигнал, а не приказ
Трекинговый параметр | tracking parameter | Метка в query (UTM, sessionid), не влияющая на контент
Главное зеркало | preferred mirror | Хост-представитель группы зеркал, на который сливаются сигналы
Бойлерплейт | boilerplate | Повторяющийся шаблонный контент (меню, футер), исключаемый из сравнения
Шингл | shingle | Пересекающаяся k-грамма токенов документа
Jaccard | Jaccard | Мера схожести множеств: пересечение / объединение
MinHash | MinHash | Сигнатура из минимумов хешей; оценивает Jaccard несмещённо
LSH | locality-sensitive hashing | Хеширование, сводящее похожие объекты в общие корзины (банды)
SimHash | SimHash | Локально-чувствительный битовый хеш; близость по расстоянию Хэмминга
Расстояние Хэмминга | Hamming distance | Число различающихся бит между двумя битовыми строками
Представитель кластера | cluster representative | Документ-дубль, попадающий в выдачу от имени всего кластера
- Опирается на Модуль 2 (Краулинг): редиректы, бюджет обхода и политика вежливости — входные сигналы каноникализатора; склейка зеркал экономит бюджет обхода.
- Питает Модуль 4 (Индексирование): индексируется канонический документ-представитель, а не каждый дубль; ключ дедупликации — основа документного идентификатора.
- Подпирает Модуль 7 (Ссылочный граф): владелец и склейка определяют, как считать и обесценивать ссылки; зеркала сливают ссылочный вес.
- Подпирает Модули 11, 16: хост/владелец как носитель поведенческих сигналов, репутации и антиспам-пессимизации.
- Связан с Модулем 15 (Группировка, схлопывание): схлопывание выдачи на уровне хоста/владельца — потребитель результатов каноникализации; near-duplicate-кластеры схлопываются в один результат.
- Связан с Модулем 17 (Свежесть): выбор первоисточника в кластере дублей опирается на время публикации.
- Классические работы по обнаружению почти-дублей в вебе (шинглинг и оценка ресемблирования множеств).
- Обзоры по MinHash и locality-sensitive hashing; разделы о similarity search в учебниках по обработке больших данных (mining of massive datasets).
- Описание SimHash и поиска по малому расстоянию Хэмминга в больших коллекциях.
- Стандарты и руководства по синтаксису URI и нормализации URL (общая теория, без привязки к продуктам).
- Обзоры по выявлению зеркал хостов и кластеризации связных компонентов в графах схожести.
- Материалы по идентификации владельцев/сетей сайтов в контексте веб-спама (обобщённо, по антиспам-литературе).