Migration 070 — добавляет houses.house_fias_id + dadata_qc_geo / qc_house / enriched_at для tracking. Скрипт scripts/backfill_houses_dadata.py проходит по ~3.8k rows с NULL coords + ~8.6k с NULL cadnum daily 100/day (DaData demo quota → ~124 дня walltime для полного прохода). Per-row SAVEPOINT, resume-safe (фильтр dadata_enriched_at IS NULL), qc_geo IN (0,1) → overwrite coord-payload, иначе только tracking. --priority coords|cadnum|both, --dry-run, --limit N (default 100). 20 тестов покрывают happy path qc_geo=0, qc_geo=3 city-level skip, DaData None response, per-row exception isolation, --dry-run, --limit, --priority filter, и missing-creds fail-fast.
62 lines
3.5 KiB
PL/PgSQL
62 lines
3.5 KiB
PL/PgSQL
-- 070_houses_dadata_enrichment.sql
|
||
-- PR Q3: DaData backfill полей на таблице `houses`.
|
||
--
|
||
-- После PR Q1 (#604) сервис `dadata.clean_address()` живёт на проде и обогащает
|
||
-- адреса estimator-flow on-demand. Этот скрипт (`scripts/backfill_houses_dadata.py`)
|
||
-- проходит по `houses` daily 100/day (DaData demo quota) и заполняет:
|
||
-- - lat / lon (3801 rows без координат)
|
||
-- - cadastral_number (12437 rows — 100% NULL)
|
||
-- - house_fias_id — НОВАЯ колонка, симметрия с trade_in_estimates.house_fias_id (PR Q1)
|
||
--
|
||
-- Колонки dadata_qc_geo / dadata_qc_house / dadata_enriched_at — tracking:
|
||
-- помечают что попытка enrichment была сделана, даже если результат не записан
|
||
-- (quality codes 2/3/4 — слишком низкое разрешение, не overwrite coords).
|
||
-- Это позволяет:
|
||
-- 1) resume-safe backfill: `WHERE dadata_enriched_at IS NULL` пропускает обработанные
|
||
-- 2) re-enrich stale: при необходимости фильтр `dadata_enriched_at < NOW() - 30 days`
|
||
--
|
||
-- Все поля nullable + IF NOT EXISTS → миграция идемпотентна.
|
||
--
|
||
-- Dependencies: 009_houses.sql + 010_houses_alter.sql + 029_extend_matching_valuation_dynamics.sql
|
||
-- Apply after: 069_trade_in_estimates_dadata_fields.sql
|
||
|
||
BEGIN;
|
||
|
||
ALTER TABLE houses
|
||
ADD COLUMN IF NOT EXISTS house_fias_id text,
|
||
ADD COLUMN IF NOT EXISTS dadata_qc_geo integer,
|
||
ADD COLUMN IF NOT EXISTS dadata_qc_house integer,
|
||
ADD COLUMN IF NOT EXISTS dadata_enriched_at timestamptz;
|
||
|
||
-- Индекс на ФИАС для будущих JOIN'ов между houses ↔ trade_in_estimates (PR Q1).
|
||
CREATE INDEX IF NOT EXISTS houses_fias_id_idx
|
||
ON houses (house_fias_id)
|
||
WHERE house_fias_id IS NOT NULL;
|
||
|
||
-- Cadastral_number индекс уже создан в 029_extend_matching_valuation_dynamics.sql
|
||
-- (имя houses_cadastral_number_idx) и в 050_search_optimization.sql (houses_kadastr_idx2).
|
||
-- IF NOT EXISTS → no-op при повторном создании. Оставляем для idempotent docs.
|
||
CREATE INDEX IF NOT EXISTS houses_cadastral_number_idx
|
||
ON houses (cadastral_number)
|
||
WHERE cadastral_number IS NOT NULL;
|
||
|
||
-- Partial index для быстрого выбора кандидатов backfill'а:
|
||
-- `WHERE dadata_enriched_at IS NULL ORDER BY id`. После полного прохода
|
||
-- (12437 row → ~124 дня walltime) индекс схлопнется до пустого set.
|
||
CREATE INDEX IF NOT EXISTS houses_dadata_not_enriched_idx
|
||
ON houses (id)
|
||
WHERE dadata_enriched_at IS NULL;
|
||
|
||
COMMENT ON COLUMN houses.house_fias_id IS
|
||
'DaData UUID ФИАС дома (PR Q3, #604+#605 follow-up). '
|
||
'Заполняется backfill-скриптом scripts/backfill_houses_dadata.py.';
|
||
COMMENT ON COLUMN houses.dadata_qc_geo IS
|
||
'DaData qc_geo: 0=exact, 1=street, 2=settlement, 3=city. '
|
||
'Только qc_geo IN (0,1) триггерит overwrite lat/lon в backfill.';
|
||
COMMENT ON COLUMN houses.dadata_qc_house IS
|
||
'DaData qc_house: 2=в ФИАС, 10=на картах, иначе не найден.';
|
||
COMMENT ON COLUMN houses.dadata_enriched_at IS
|
||
'Когда последний раз пробовали enrich через DaData (NULL = ни разу). '
|
||
'Используется для resume-safe backfill — `WHERE dadata_enriched_at IS NULL`.';
|
||
|
||
COMMIT;
|