fix(tradein): avito houses dedup через match_or_create_house + merge-миграция дублей (108) #1546
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#1546
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/avito-houses-dedup-merge"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Проблема
Таблица
housesнакопила ~4479 лишних строк (~33%): один физический дом создавался многократно. Корень —avito_houses.py::upsert_house/_upsert_house_with_urlделали прямойINSERT INTO houses ON CONFLICT (source, ext_house_id), минуяmatch_or_create_house. Конфликт-ключ — avito building-id, поэтому дедуп по кадастру/адресу/гео никогда не запускался → каждый catalog-enrich плодил новый дом. Все остальные пути (listing-скрапперbase.py, estimator) уже ходят черезmatch_or_create_houseкорректно — avito_houses был единственным bypass.Подтверждённая картина (живая БД): 3879 групп с одинаковым адресом + 1888 групп по координатам. Часть «у дома много объявлений» (
listings.house_id_fk, avg 2.8/дом) работала и не трогается.Изменения
1. Forward-fix
avito_houses.py— новый_persist_house(db, h, house_url):match_or_create_house(ext_source="avito", ext_id=str(h.ext_id), address=short_address, lat, lon, year_built, source_url)→ canonicalhouse_id(3-tier дедуп +pg_advisory_xact_lock);UPDATE houses SET …со всеми 30+ enrichment-полями. avito-авторитетные (rating/developer/тех-хар-ки/map_pins/raw_characteristics) — прямое присвоение;address/lat/lon/year_built— черезCOALESCE(houses.<col>, …)чтобы не затирать canonical от cian/кадастра;db.commit()только вsave_house_catalog_enrichment(advisory lock держится весь pipeline).address=short_address(не full): существующиеhouse_address_aliasesлежат в short-форме без регионального префикса — full дал бы промах по Tier 2 (review M1, проверено по проду).2. Merge-миграция
data/sql/108_merge_duplicate_houses.sql(идемпотентна,BEGIN/COMMIT, авто-применяется на прод):addr:lower(address)→geo:round(lat/lon,4); строки без всех трёх пропускаются (консервативно — лучше недо-слить);ROW_NUMBER() OVER (… ORDER BY geom IS NOT NULL DESC, field_count DESC, id ASC);listings.house_id_fk,house_sources,house_address_aliases,house_reviews,house_placement_history,houses_price_dynamics,house_reliability_checks,house_imv_evaluations,house_suggestions,external_valuations,address_mismatch_audit) доDELETE FROM houses— с обработкой UNIQUE-коллизий (delete-dup-before-repoint для таблиц с уникальными ключами);house_sources/house_address_aliasesдля канонов (ON CONFLICT DO NOTHING);RAISE NOTICEbefore/after counts.3. Тест
tests/test_avito_houses_dedup.py— роутинг через matching + запись enrichment-полей.Проверки
test_cian_valuation::test_cache_hit(воспроизводится на main).short_address), остальные minor by-design.⚠️ Деплой
Миграция 108 деструктивна (удаляет ~тысячи строк houses) и авто-применяется на прод на деплое. Репойнт идёт до delete — данные зависимых таблиц сохраняются на канонических домах. Точный count смерженных кластеров — в
RAISE NOTICEпервого деплоя.