Когда вы собираете объявления с нескольких площадок, дубли появляются почти сразу. Один и тот же объект публикуют разные риелторы, собственник и агентство, причём в разных форматах: где-то полный адрес, где-то только район и ориентир, у одной записи свежие фото, у другой — актуальная цена. Чтобы агрегация стала полезной, недостаточно просто загрузить данные в базу. Нужно уметь сводить их в одну карточку объекта без потери качества и без ложных объединений, которые ломают выдачу и подрывают доверие пользователя.
Почему дубли в недвижимости — это не просто «повтор»
В недвижимости дубль — это не идентичная строка, а часто тот же объект, описанный по-разному. Один источник может указать полный адрес, другой — только район и ориентир. У одного объявления будут свежие фото, у другого — актуальная цена. Если склеить такие записи неправильно, пользователь увидит мусор вместо полезной выдачи: пять карточек одной и той же квартиры с разными ценами и наборами фотографий.
Проблема особенно заметна в аренде и вторичке: один объект может несколько раз попадать в выдачу из-за кросс-постинга, обновления объявления, изменения цены или смены посредника. Поэтому задача дедупликации — не «удалить лишнее», а понять, какие записи относятся к одному реальному объекту. И это не разовая операция, а постоянный процесс в пайплайне агрегатора.
Что считать дублем, а что — похожим объявлением
Перед настройкой алгоритма важно разделить три сценария, потому что от этого зависит порог уверенности и дальнейшие действия системы:
- Точный дубль — записи совпадают почти полностью: один и тот же URL, одинаковые поля, те же фото. Так бывает при повторной публикации с одной площадки или копировании.
- Вероятный дубль — объявление отличается в деталях, но адрес, площадь, этаж, планировка и фото указывают на один объект. Классический случай: собственник выложил объявление сам, а через неделю его же разместило агентство с новыми фотографиями и другой ценой.
- Похожий, но не дубль — квартира в том же доме, но другая секция, этаж, корпус или планировка. Иногда отличить можно только по планировке или номеру квартиры, если он есть.
Это критично: если дедупликация слишком агрессивная, система начнёт склеивать разные квартиры и пользователь потеряет реальные варианты. Если слишком слабая — пользователь утонет в повторах и перестанет доверять выдаче.
Из каких признаков обычно собирают сигнал
На практике лучше смотреть не на один признак, а на набор полей. Чем больше независимых совпадений, тем выше уверенность. В реальных проектах я обычно комбинирую несколько источников сигнала, потому что ни одно поле не даёт стопроцентной гарантии.
| Признак | Что показывает | Насколько полезен |
|---|---|---|
| Адрес | Базовая привязка к объекту | Очень высокий |
| Координаты | Точное местоположение | Очень высокий |
| Площадь | Хороший идентификатор для квартиры | Высокий |
| Цена | Сильный, но изменчивый сигнал | Средний |
| Этаж и этажность | Помогают отличать похожие объекты | Высокий |
| Количество комнат | Уточняет тип объекта | Средний |
| Фото | Часто лучший визуальный маркер | Очень высокий |
| Описание | Полезно, но шумное поле | Средний |
| Телефон/контакт | Сильный источник связи между объявлениями | Очень высокий |
| Источник и ссылка | Помогают отличать повторную публикацию | Высокий |
Рабочая схема дедупликации
Для реальных проектов лучше использовать не один алгоритм, а несколько этапов. Такой подход устойчивее, чем попытка решить всё одной формулой. Ниже — проверенная на практике последовательность, которую можно подстроить под объёмы и особенности источников.
1. Нормализация данных
Сначала все объявления приводятся к единому виду. Без этого два одинаковых объекта могут выглядеть как совершенно разные записи. В моих парсерах этот этап занимает больше всего времени на старте: нужно продумать словари синонимов, регулярные выражения для извлечения чисел и единый формат для адресов.
- адреса очищаются от лишних сокращений;
- единицы измерения приводятся к одному формату;
- цена переводится в одну валюту и один тип значения;
- площади и этажи записываются как числа;
- телефоны и ссылки нормализуются;
- названия улиц, корпусов и ЖК унифицируются.
Например, «ул. Ленина, д. 5, к. 2» и «Ленина 5/2» после нормализации должны стать одной строкой. Если этого не сделать, сравнение по точному совпадению не сработает.
2. Быстрый поиск кандидатов
Нельзя сравнивать каждое объявление со всеми остальными: при больших объёмах это слишком дорого. Поэтому сначала отбирают кандидатов на совпадение по грубым фильтрам:
- один город или район;
- похожий адрес;
- совпадающая комнатность;
- близкая площадь;
- один временной диапазон публикации.
Этот этап нужен, чтобы сократить число пар для проверки. В продакшене я использую индексы по нормализованным полям и блокирующие ключи: например, первые 6 символов от хеша адреса или комбинация «район + комнатность + площадь, округлённая до ближайших 5 м²». Такое «грубое» отсечение снижает вычислительную сложность с O(n²) до чего-то управляемого.
3. Оценка схожести
После отбора кандидатов считается общий score. Обычно он строится из нескольких частичных совпадений:
- адрес совпал полностью — высокий балл;
- площадь отличается незначительно — добавляем баллы;
- фото визуально похожи — ещё один сильный сигнал;
- описание пересекается по ключевым фразам — дополнительный аргумент;
- телефон совпал — почти прямое подтверждение.
Важно не полагаться на один критерий. Например, цена может меняться, а в описании могут быть маркетинговые правки. Зато адрес, планировка и фото часто дают более надёжную картину. Для сравнения фото я использую perceptual hash: считаем средний хеш по уменьшенному изображению и сравниваем расстояние Хэмминга. Это быстро и отсекает большинство дублей, хотя и не идеально для разных ракурсов.
4. Группировка в кластеры
Если несколько объявлений относятся к одному объекту, их нужно объединить не попарно, а в кластер. Это значит, что система хранит одну сущность — объект недвижимости — и привязывает к ней все найденные публикации.
Такой подход удобен для пользователя: он видит не десять одинаковых карточек, а одну карточку с источниками. Технически это можно реализовать через union-find или граф, где узлы — объявления, а рёбра — совпадения выше порога. На выходе каждая компонента связности становится канонической карточкой с привязанными записями.
Как понять, что это один и тот же объект
Ниже — практическая логика, которая подходит для большинства real estate-проектов. Она основана на комбинации признаков и уровнях уверенности, которые можно настроить под конкретные источники.
Высокая вероятность дубля
Считайте записи дублем, если совпадает хотя бы один сильный набор признаков:
- точный адрес + почти одинаковая площадь + совпадающие фото;
- координаты + этаж + комнатность + похожее описание;
- одинаковый контакт + адрес + объектные параметры.
Средняя вероятность
Случай требует ручной проверки, если:
- адрес неполный;
- фото отличаются, но есть похожая планировка;
- цена отличается заметно, но остальные параметры совпадают;
- объект опубликован на разных площадках в разное время.
Низкая вероятность
Скорее всего это разные объекты, если:
- совпадает только район;
- площадь и этаж отличаются существенно;
- фото не пересекаются;
- адрес указан расплывчато.
Типовые ошибки при объединении объявлений
За годы работы с агрегаторами я наступил на все эти грабли. Лучше знать их заранее, чем отлаживать ложные склейки в проде.
Ошибка 1. Слепая склейка по адресу
Один дом — это ещё не один объект. В большом доме может быть много одинаковых по метражу квартир. Без дополнительных признаков вы получите ложные совпадения. Например, в новостройке на 500 квартир адрес «улица Строителей, дом 10» ничего не говорит о конкретной квартире. Нужны этаж, планировка, номер квартиры или хотя бы фото.
Ошибка 2. Игнорирование изменений цены
Цена часто меняется, и это не повод считать объявление новым объектом. Но если цена сильно отличается вместе с другими полями, это может быть как новый источник, так и другая квартира. Лучше хранить историю цен и использовать цену как дополнительный сигнал, а не как решающий.
Ошибка 3. Доверие только тексту
Описание легко переписать. Риелторы часто меняют формулировки, добавляют маркетинговые слова или скрывают контакты. Текст хорош как вспомогательный сигнал, но не как единственный. Я обычно использую cosine similarity по TF-IDF или embedding’ам, но с низким весом, потому что описания слишком изменчивы.
Ошибка 4. Отсутствие приоритетов источников
Если источники отличаются качеством данных, нужен порядок доверия. Например, один источник может быть богаче по фото, другой — точнее по географии, третий — быстрее обновляться. Без приоритетов вы получите кашу в канонической карточке: устаревшая цена с одного источника, размытое фото с другого, неполный адрес с третьего.
Ошибка 5. Неучёт времени
Объявление могло быть снято и опубликовано заново. Если не учитывать дату и историю, система будет путать новый объект с архивной записью. Особенно это важно в аренде, где квартира может вернуться на рынок через полгода с новым ремонтом и ценой. Нужно вести историю статусов и уметь различать «снова активно» и «новый объект».
Как выбирать «главную» карточку среди дублей
После группировки нужно решить, какая запись станет основной. Обычно выбирают не «самую первую», а самую полезную.
Критерии выбора канонической записи
- больше заполненных полей;
- более свежие данные;
- лучшие фото;
- точнее адрес;
- меньше ошибок и пропусков;
- выше доверие к источнику.
Хорошая практика — хранить не только основную карточку, но и все исходные версии. Тогда можно восстановить историю изменений: цена, описание, наличие мебели, статус публикации. В архитектуре это обычно означает отдельную таблицу для канонических объектов и таблицу связей с исходными записями.
Что делать с конфликтующими данными
Иногда разные источники противоречат друг другу. Например, в одном объявлении 42 м², в другом 44 м². В таких случаях не стоит бездумно перезаписывать одно другим.
Рабочий подход такой:
- для каждого поля задаётся приоритет источника;
- конфликтные значения сохраняются в истории;
- для пользователя показывается одно основное значение и при необходимости — уточнение;
- если поле критичное, запись уходит на ручную проверку.
Особенно это важно для адреса, площади, комнатности и этажа. Ошибка в таких полях ломает всю дедупликацию дальше по цепочке. Я обычно ввожу систему «доверия» для каждого источника по каждому типу поля: например, источник A даёт точный адрес, но кривую площадь, а источник B — наоборот.
Пошаговый процесс для небольшого проекта
Если система только запускается, не усложняйте архитектуру раньше времени. Можно начать с понятного и надёжного пайплайна, который потом легко масштабировать.
Шаг 1. Приведите поля к единому формату
Соберите единый словарь адресов, форматов цен, площадей и типов объектов. Начните с самых частых источников и выпишите все вариации написания улиц, микрорайонов и ЖК.
Шаг 2. Настройте простые правила
Например:
- совпадение точного адреса;
- разница по площади не больше 2 м²;
- разница по цене не больше 5–10%;
- совпадение фото или телефона увеличивает уверенность.
Шаг 3. Сгруппируйте кандидатов
Сначала объединяйте только очевидные случаи. Всё спорное — в очередь на проверку. Не пытайтесь сразу автоматизировать все пограничные кейсы, иначе закопаетесь в отладке.
Шаг 4. Введите статус уверенности
У карточки должен быть не только результат, но и уровень доверия: высокий, средний, низкий. Это поможет приоритизировать ручную проверку и отслеживать качество.
Шаг 5. Сохраняйте историю
Храните связь между канонической записью и источниками. Это пригодится для отладки, аналитики и повторной проверки. Как минимум, пишите в лог, какие пары были объединены и по каким правилам.
Чек-лист для настройки дедупликации
- Все адреса приведены к единому формату
- Площадь, цена, этаж и комнатность нормализованы
- Фото сравниваются хотя бы на базовом уровне
- Есть правила отбора кандидатов
- Есть пороги для уверенного и спорного совпадения
- Назначен приоритет источников
- Сохраняется история изменений
- Спорные случаи отправляются на ручную проверку
- Ложные совпадения отслеживаются и используются для улучшения правил
Когда без ручной проверки не обойтись
Автоматизация хорошо работает на больших объёмах, но полностью исключить ручную проверку нельзя. Она нужна, если:
- адрес неполный или скрыт;
- объект в новостройке без точной привязки;
- много похожих квартир в одном доме;
- фото одинакового качества и почти неразличимы;
- данные пришли из источника с низкой точностью.
В зрелых системах ручная проверка нужна не для всех записей, а только для пограничных случаев. Это экономит время и повышает качество базы. Обычно такой интерфейс встраивают в админку: оператор видит пару кандидатов, исходные данные и кнопки «объединить» или «разделить».
Практический вывод
Объединение объявлений без дублей — это не одна функция, а цепочка из нормализации, отбора кандидатов, оценки схожести, группировки и контроля конфликтов. Чем больше сигналов система учитывает, тем меньше мусора увидит пользователь и тем полезнее будет агрегатор.
Если делать всё правильно, одна реальная квартира перестаёт превращаться в десять похожих карточек, а пользователь получает чистую, понятную выдачу с историей и источниками. И это, в конечном счёте, главная метрика успеха вашего агрегатора.
FAQ
Какой признак самый надёжный для поиска дублей?
Самые сильные сигналы — точный адрес, координаты, телефон и фото. Но надёжнее всего работает их комбинация, а не один признак. Я бы не стал полагаться только на телефон: его могут скрыть или сменить.
Можно ли объединять объявления только по цене и площади?
Нет. Эти поля полезны, но слишком часто совпадают у разных объектов. Без адреса, фото или дополнительных маркеров будут ложные склейки. Например, в одном доме может быть десяток квартир с одинаковой площадью и ценой.
Что делать, если одно объявление от собственника, а другое от риелтора?
Это частый случай. Если параметры объекта совпадают, такие записи обычно нужно объединять в одну карточку, но с сохранением всех источников. Пользователю не важно, кто разместил объявление, ему нужен сам объект.
Нужно ли хранить удалённые дубликаты?
Да. Лучше хранить не удаление, а связь с канонической записью и историю изменений. Это помогает анализировать рынок и отлаживать дедупликацию. Удалённые записи могут пригодиться, если правила поменяются.
Какой подход лучше: правила или ML-модель?
Для старта — правила и нормализация. Для больших объёмов и сложных кейсов лучше гибридный подход: правила для очевидных совпадений, модель для спорных. ML-модель можно обучить на размеченных вручную парах, когда накопится достаточно данных.
