Co-authored-by: bot-backend <bot-backend@gendsgn.local> Co-committed-by: bot-backend <bot-backend@gendsgn.local>
75 lines
4.8 KiB
PL/PgSQL
75 lines
4.8 KiB
PL/PgSQL
-- 140_ekb_krt_geometry.sql
|
||
-- #1130 (Site Finder v2 / GG-форсайт) — КРТ-геометрии геопортала ЕКБ в БД.
|
||
--
|
||
-- Слой portal_geo_oks_krt («Здания в границах КРТ») → ~48 WFS-фич с Polygon-геометриями.
|
||
-- Harvest-воркер (krt_geometry_sync.py) раз в неделю UPSERT-ит сюда все фичи одним bbox-запросом.
|
||
-- analyze читает _krt_at через ST_Intersects(geom, point) — без живого WFS-вызова в hot-пути.
|
||
--
|
||
-- UNIQUE-ключ: feature_id — стабильный строковый id WFS-фичи GeoServer
|
||
-- (вида «portal_geo_oks_krt.NNN»; trailing-int выделяется для numeric lookup).
|
||
-- Выбор обоснован: GeoServer feature_id стабилен между запросами одного слоя (это PK GeoServer),
|
||
-- не зависит от изменяемых атрибутов (num_oks_krt/status/area) и присутствует у каждой фичи.
|
||
-- Альтернатива (num_oks_krt+MD5(geom)) нестабильна при минимальных правках геометрии → излишний
|
||
-- DELETE+INSERT вместо UPDATE; feature_id надёжнее.
|
||
--
|
||
-- Deploy: auto-applied deploy.yml через _schema_migrations (ровно один раз по NN).
|
||
-- Idempotent (CREATE TABLE/INDEX IF NOT EXISTS + guarded DO-блок для UNIQUE).
|
||
-- Зеркалит pattern м.132 (ird_overlays) и м.137 (ekb_krt_sites).
|
||
-- Без INSERT — данные приходят из Celery-воркера krt_geometry_sync.
|
||
|
||
BEGIN;
|
||
|
||
-- ── 1. Таблица ekb_krt_geometry ──────────────────────────────────────────────
|
||
CREATE TABLE IF NOT EXISTS ekb_krt_geometry (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
feature_id TEXT NOT NULL, -- GeoServer WFS feature id («portal_geo_oks_krt.7»)
|
||
num_oks_krt INTEGER, -- порядковый номер КРТ-площадки
|
||
full_name TEXT, -- полное наименование (из свойств слоя)
|
||
status TEXT, -- статус КРТ («В работе», «Завершён» и т.п.)
|
||
geom geometry(Geometry, 4326) NOT NULL, -- полигон КРТ-территории, EPSG:4326
|
||
area NUMERIC, -- площадь из свойств (га или кв. м — как в слое)
|
||
raw_props JSONB, -- полный properties-объект WFS-фичи (forward-compat)
|
||
fetched_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
COMMENT ON TABLE ekb_krt_geometry IS
|
||
'Геометрия КРТ-территорий ЕКБ (#1130, GG-форсайт). '
|
||
'Источник: WFS-слой portal_geo_oks_krt геопортала ЕКБ (~48 фич). '
|
||
'Harvest — Celery krt_geometry_sync раз в неделю (bbox ЕКБ-агломерации). '
|
||
'analyze._krt_at читает ST_Intersects(geom, point) вместо живого WFS-вызова.';
|
||
|
||
COMMENT ON COLUMN ekb_krt_geometry.feature_id IS
|
||
'Стабильный GeoServer WFS feature id слоя («portal_geo_oks_krt.7»). UNIQUE ON CONFLICT target.';
|
||
COMMENT ON COLUMN ekb_krt_geometry.num_oks_krt IS
|
||
'Порядковый номер КРТ-площадки из свойств WFS-фичи (num_oks_krt). NULL если не задан.';
|
||
COMMENT ON COLUMN ekb_krt_geometry.geom IS
|
||
'Polygon/MultiPolygon КРТ-территории в EPSG:4326 (WFS GeoServer отдаёт в 4326 напрямую).';
|
||
|
||
-- ── 2. UNIQUE по feature_id (ON CONFLICT target для UPSERT) ─────────────────
|
||
DO $$
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = 'uq_ekb_krt_geometry_feature_id'
|
||
) THEN
|
||
ALTER TABLE ekb_krt_geometry
|
||
ADD CONSTRAINT uq_ekb_krt_geometry_feature_id
|
||
UNIQUE (feature_id);
|
||
END IF;
|
||
END
|
||
$$;
|
||
|
||
-- ── 3. Индексы ───────────────────────────────────────────────────────────────
|
||
-- ГЛАВНЫЙ read-path: ST_Intersects(geom, point) из _krt_at в analyze hot-пути.
|
||
CREATE INDEX IF NOT EXISTS idx_ekb_krt_geometry_geom
|
||
ON ekb_krt_geometry USING GIST (geom);
|
||
|
||
-- Lookup по порядковому номеру (JOIN к ekb_krt_sites по num_oks_krt).
|
||
CREATE INDEX IF NOT EXISTS idx_ekb_krt_geometry_num_oks_krt
|
||
ON ekb_krt_geometry (num_oks_krt)
|
||
WHERE num_oks_krt IS NOT NULL;
|
||
|
||
-- Мониторинг свежести данных.
|
||
CREATE INDEX IF NOT EXISTS idx_ekb_krt_geometry_fetched_at
|
||
ON ekb_krt_geometry (fetched_at DESC);
|
||
|
||
COMMIT;
|