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
Скрапер знает город в момент сбора (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 задачи.
44 lines
3.3 KiB
PL/PgSQL
44 lines
3.3 KiB
PL/PgSQL
-- 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;
|