gendesign/tradein-mvp/backend/data/sql/196_listings_city.sql
bot-backend 0a4e126b30
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 9s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 2m28s
fix(tradein/scraper): проставлять город объявления из контекста развёртки (#2594)
Скрапер знает город в момент сбора (city_slug из CITY_LOCATIONS/CITY_ANCHORS,
scraper_kit.orchestration.pipeline), но раньше нигде его не записывал. Провайдеры
(avito/cian) часто отдают адрес БЕЗ города в тексте ("ул. Победы, 30" вместо
"Нижний Тагил, ул. Победы, 30" — cian даже явно вырезает location-часть перед
записью, providers/cian/serp.py _format_address skip_types={"location",...}).
Без города такой адрес при геокодинге считался "город не назван" и коллизировал
с одноимённой екатеринбургской улицей (Ленина/Победы/Тенистая — сотни совпадений
в ЕКБ-реестрах) → объявление получало координаты Екатеринбурга.

Fix: отдельная колонка listings.city (196_listings_city.sql), проставляется из
sweep-контекста через save_listings(..., city=...) — НЕ парсингом/дописыванием
в address. Раздельная колонка не портит исходный текст адреса: downstream
text-парсеры (geocoder._parse_street_house/_names_non_ekb_city, estimator
house-matching) продолжают работать на исходном сыром тексте неизменёнными —
дописывание города в address ломало бы bare-form адреса без street-маркера
("Дружинина, 33" без "ул.") в этих же парсерах.

Симметрия: EKB-варианты city-sweep функций (city_slug=None) тоже получают
city="Екатеринбург" — resolve_city_name(None) даёт тот же ЕКБ-дефолт, что и
get_city_location/get_city_anchors. Проставлено во всех продовых write-путях:
run_avito_city_sweep/run_yandex_city_sweep/run_cian_city_sweep (city_slug-aware),
run_avito_newbuilding_sweep/run_cian_full_load/run_yandex_full_load/
run_avito_full_load (подтверждённо EKB-only по докстрингам), run_domclick_city_sweep
(EKB city_id, oblast B2 ещё не wired — честный None для неизвестного city_id).

Scope: только write-path для НОВЫХ листингов. Бэкфилл накопленных строк и
консультация city в geocode_missing_listings/backfill_coords_from_geoportal
(gate там пока text-only, _names_non_ekb_city) — geocoder.py намеренно не
тронут (#2582/#2580) — отдельные follow-up задачи.
2026-07-31 22:14:47 +03:00

44 lines
3.3 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 196_listings_city.sql
-- Issue #2594 — критичный дефект: скрапер знает город в момент сбора (city_slug из
-- CITY_LOCATIONS/CITY_ANCHORS, packages/scraper-kit/.../orchestration/pipeline.py), но
-- НИКУДА его не пишет. Провайдеры (avito/cian) часто отдают адрес БЕЗ города в тексте
-- ("ул. Победы, 30" вместо "Нижний Тагил, ул. Победы, 30") — cian даже явно вырезает
-- location-часть перед записью (skip_types = {"location", "metro"}, providers/cian/serp.py).
-- Без явного города такой адрес при геокодинге считается «город не назван» → попадает
-- в EKB-only локальные реестры (ekb_geoportal_buildings/gendesign_cad_buildings) и
-- коллизирует с одноимённой екатеринбургской улицей (Ленина/Победы/Тенистая — сотни
-- совпадений) → объявление получает координаты Екатеринбурга и тянет медиану чужих цен.
--
-- Fix:
-- Add listings.city TEXT column. Проставляется НЕПОСРЕДСТВЕННО из контекста
-- развёртки (город известен вызывающему коду — city_slug/CITY_LOCATIONS для oblast,
-- "Екатеринбург" для EKB-развёрток) — НЕ парсингом текста адреса. См.
-- scraper_kit.base.save_listings(..., city=...) + scraper_kit.orchestration.pipeline
-- .resolve_city_name(). Раздельная колонка (а не дописывание города в address) —
-- исходный текст адреса не портится, downstream text-парсеры (geocoder._parse_street_house,
-- geocoder._names_non_ekb_city, estimator._parse_street_house, house-matching) продолжают
-- работать НЕИЗМЕНЁННЫМИ на исходном сыром тексте — риск регрессии на bare-form адресах
-- без street-маркера ("Дружинина, 33") исключён.
--
-- Scope (#2594): только write-path для НОВЫХ листингов (go-forward). Бэкфилл city для
-- уже накопленных строк (restore по тому, какая развёртка их когда-то принесла) —
-- отдельная задача, НЕ эта миграция.
--
-- Idempotency:
-- ALTER TABLE ... ADD COLUMN IF NOT EXISTS — safe on re-run.
-- BEGIN/COMMIT block.
--
-- Dependencies:
-- 002_core_tables.sql (listings table).
BEGIN;
ALTER TABLE listings ADD COLUMN IF NOT EXISTS city text;
COMMENT ON COLUMN listings.city IS
'Город объявления (#2594) — проставляется из контекста развёртки '
'(city_slug city-sweep / "Екатеринбург" default), НЕ парсингом address. '
'NULL — листинг записан до этой миграции ИЛИ путём, ещё не проставляющим город '
'(admin ad-hoc /admin/scrape, manual ingest-скрипты).';
COMMIT;