gendesign/data/sql/63_schema_nspd_runs.sql
lekss361 25b73035a1 sprint1: nspd scraper industrialization, per-bucket elasticity, cadastre cross-check, sentry releases
- NSPD-skraper переехал в backend/app/services/scrapers/nspd_kn.py +
  Celery task scrape_nspd_region (beat: 20-е февраля/мая/авг/нояб).
  Redis lock 3h, WAF auto-retry, heartbeat в nspd_scrape_runs.
- Recommend_mix Tier 3: per-bucket elasticity через регрессию по
  «доминирующему bucket» каждого ЖК. Weighted-elasticity для inverse-mode.
  UI показывает разброс эластичностей и переключение regression/fallback.
- Cadastre vs market cross-check: spatial-join cad_buildings →
  ekb_districts_geom; cadastre_vs_market_pct в scope, аномалии
  (>+50% / <-30%) подсвечены в UI.
- Sentry release tracking (#4): IMAGE_TAG → backend/.env.runtime →
  sentry_sdk.init(release=...). Compose v2 env_file optional path.

Schemas: 63_schema_nspd_runs.sql (cad_buildings + nspd_scrape_runs/log
формализуют то, что уже жило в проде через 61_import_nspd_batch.py),
64_v_zk_rosreestr_velocity.sql (refresh с cad_buildings).
2026-04-30 21:51:19 +03:00

94 lines
4.7 KiB
SQL
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.

-- NSPD scrape industrialization: schema baseline.
--
-- 1. cad_buildings — формальная DDL для таблицы, которая создавалась
-- напрямую в проде через 61_import_nspd_batch.py (10590 зданий ЕКБ
-- на момент 2026-04-30). IF NOT EXISTS — миграция идемпотентна.
-- 2. nspd_scrape_runs — журнал автоматизированных Celery-запусков
-- (по образцу kn_scrape_runs из 50_schema_kn_extensions.sql).
-- 3. nspd_scrape_log — построчный лог стадий (по образцу kn_scrape_log).
CREATE EXTENSION IF NOT EXISTS postgis;
-- ── 1. cad_buildings ─────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS cad_buildings (
cad_num TEXT PRIMARY KEY,
quarter_cad_num TEXT REFERENCES cad_quarters_geom(cad_number) ON DELETE SET NULL,
geom geometry(Geometry, 4326),
purpose TEXT,
building_name TEXT,
readable_address TEXT,
area NUMERIC,
floors INT,
year_built INT,
year_commisioning INT,
cost_value NUMERIC,
registration_date DATE,
status TEXT,
ownership_type TEXT,
cultural_heritage TEXT,
underground_floors INT,
build_record_area NUMERIC,
build_record_type TEXT,
common_data_status TEXT,
obj_type TEXT,
raw_props jsonb,
fetched_at timestamptz NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS cad_buildings_geom_gist
ON cad_buildings USING GIST (geom);
CREATE INDEX IF NOT EXISTS cad_buildings_quarter_idx
ON cad_buildings(quarter_cad_num);
CREATE INDEX IF NOT EXISTS cad_buildings_purpose_idx
ON cad_buildings(purpose);
COMMENT ON TABLE cad_buildings IS
'Здания (НСПД thematicSearchId=1) внутри cad_quarters_geom. '
'Источник cost_value для cross-check с sale_graph.';
-- ── 2. nspd_scrape_runs ──────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS nspd_scrape_runs (
run_id BIGSERIAL PRIMARY KEY,
started_at timestamptz NOT NULL DEFAULT NOW(),
finished_at timestamptz,
heartbeat_at timestamptz,
region_code INT NOT NULL,
pending_count INT,
quarters_ok INT NOT NULL DEFAULT 0,
quarters_failed INT NOT NULL DEFAULT 0,
buildings_ok INT NOT NULL DEFAULT 0,
requests_count INT NOT NULL DEFAULT 0,
waf_429_count INT NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'running', -- running | done | failed | zombie | skipped
error TEXT,
triggered_by TEXT NOT NULL DEFAULT 'beat' -- beat | manual | resume
);
CREATE INDEX IF NOT EXISTS nspd_runs_status_idx
ON nspd_scrape_runs(status, started_at DESC);
CREATE INDEX IF NOT EXISTS nspd_runs_region_idx
ON nspd_scrape_runs(region_code, started_at DESC);
COMMENT ON TABLE nspd_scrape_runs IS
'Журнал NSPD-скрейпов кадастровых кварталов и зданий. Один прогон на регион. '
'Beat-расписание: 20-е число февраля/мая/августа/ноября (после кв. публикаций rosreestr).';
-- ── 3. nspd_scrape_log ───────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS nspd_scrape_log (
log_id BIGSERIAL PRIMARY KEY,
run_id BIGINT REFERENCES nspd_scrape_runs(run_id) ON DELETE CASCADE,
ts timestamptz NOT NULL DEFAULT NOW(),
level TEXT NOT NULL DEFAULT 'info', -- debug | info | warn | error
stage TEXT, -- task_received | discover | quarter_fetch | buildings | commit | done | error
cad_number TEXT,
message TEXT
);
CREATE INDEX IF NOT EXISTS nspd_log_run_idx
ON nspd_scrape_log(run_id, ts DESC);
CREATE INDEX IF NOT EXISTS nspd_log_level_idx
ON nspd_scrape_log(level, ts DESC) WHERE level IN ('warn', 'error');
COMMENT ON TABLE nspd_scrape_log IS
'Построчный лог NSPD-скрейпа: какие cad-кварталы успешны/упали, '
'WAF-403 ретраи, фазы commit. Используется UI /scrape/nspd для мониторинга.';