fix(tradein/tasks): городской гейт в ночном бэкфилле координат (#2583) #2588
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
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#2588
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/tradein-coords-backfill-city-gate"
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?
Находка H3 из аудита #2583 — единственный дефект, который портил данные каждую ночь, а не только выдавал неверный ответ по запросу.
backfill_listings_coords_geoportal.pyбрала все объявления без координат, парсила адрес (город при этом отбрасывается) и звала екатеринбургский реестр напрямую, минуяgeocode()— то есть городской гейт не применялся вообще. Объявление из Тагила получало координаты Екатеринбурга, после чего тянуло медиану чужих оценок, исчезало из выборки своего города и приклеивалось к екатеринбургскому дому при сопоставлении по расстоянию. Задача включена, без лимита, в окне 05:00-06:00 — выигрывала гонку у областного геокодера (06:00-09:00).Решение: проверка
_names_non_ekb_city(address)перед обращением к реестру — та же функция, что уже гейтит эти тиры внутриgeocode(). Полноценныйgeocode()намеренно не используется: он добавил бы вызовы внешних геокодеров на каждый областной адрес из очереди (сотни-тысячи за ночь), а Яндекс сейчас отдаёт 403 (#2585) и живой только Nominatim с паузами. Прямой матчер остаётся локальной операцией по БД.Порядок окон не менялся: после фикса областные адреса здесь просто не матчатся и остаются ждать корректного геокодера в следующем окне — ровно как раньше вели себя адреса без совпадения в реестре.
geo_precisionосознанно остаётсяNULL: по конвенции (089_listings_geo_precision.sql,geocode_missing.pyи его тест)NULLозначает «не coarse» — то же значение, что у точных адресов. Этот тир всегда даёт попадание на уровне дома, поэтому фильтр, исключающий'city', для него срабатывать и не должен.Масштаб уже нанесённого ущерба (только SELECT, ничего не менялось): 2040 объявлений имеют координаты внутри границ Екатеринбурга при адресе, называющем другой город региона; 1941 после исключения омонимов-новостроек («ЖК Заречный», «Берёзовский» — реальные названия внутри самого ЕКБ). ⚠️ Но только ~31 из них совпадают по координатам с екатеринбургскими реестрами — значит основная масса пришла не от этой задачи, а из других источников координат (GPS в карточках Авито у приграничных спутников). Перед чисткой нужна точная атрибуция источника — это отдельный шаг, здесь не делается.
Тесты: объявление другого города не матчится, екатеринбургское матчится как раньше. Оба падали на старом коде (проверено откатом только рабочего файла). Полный прогон: 2847 passed, 1 pre-existing. Также поправлен ложный комментарий в миграции 171 («не-ЕКБ адреса не матчатся — корректно»), который и закреплял ошибочную посылку.
backfill_coords_from_geoportal брал все listings с lat IS NULL, парсил street+house и матчил напрямую против EKB-only ekb_geoportal_buildings, минуя geocoder.geocode() и его городской гейт (_names_non_ekb_city). Улица+дом могут буквально совпасть между Екатеринбургом и другим городом области ("проспект Ленина 1" есть и в ЕКБ, и в Нижнем Тагиле) — такие адреса получали екатеринбургские координаты и портили радиусные выборки аналогов на этой улице в ЕКБ, а сами исчезали из выборки своего города. Фикс: _names_non_ekb_city(address) перед вызовом _geoportal_house_match — тот же гейт, что уже используется в geocode(). Прямой вызов geoportal-матчера (а не полноценный geocode()) сохранён намеренно — pure local-DB операция без внешнего HTTP, полноценный geocode() добавил бы Nominatim/Yandex вызов на каждый non-EKB адрес backlog'а (лишняя нагрузка на ограниченный Nominatim, Yandex сейчас 403 — #2585). geo_precision оставлен NULL для house-level матчей этого тира — по конвенции 089_listings_geo_precision.sql/geocode_missing.py NULL означает "не coarse", то же значение что geo_precision=None для precise-адресов в geocode_missing_listings; исключать из radius-аналогов нужно только 'city'-fallback. Порядок окон (05:00 geoportal → 06:00 geocode_missing_listings) не менялся: гонка была безвредна для корректно заматченных EKB-адресов, вредна только из-за отсутствия гейта — теперь non-EKB адреса здесь не матчатся вообще и просто ждут oblast-aware провайдеров в следующем окне. Поправлен ложный комментарий в migration 171 ("не-ЕКБ адреса не матчатся — корректно"). Ущерб на проде (SELECT-only, без изменений): 2040 листингов с координатами внутри EKB-bbox (56.65-56.95, 60.40-60.85) при адресе, называющем другой город области (1941 после исключения мкр/р-н/жк-омонимов вроде ЖК "Заречный" внутри ЕКБ). Только ~31 из них совпадают по координатам с ekb_geoportal_buildings/gendesign_cad_buildings — основной массив, вероятно, из других источников координат (не только этот таск). Чистка — отдельный шаг.