All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 4m9s
Deploy Trade-In / build-backend (push) Successful in 1m54s
Deploy Trade-In / deploy (push) Successful in 1m51s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 11s
79 lines
5.7 KiB
PL/PgSQL
79 lines
5.7 KiB
PL/PgSQL
-- 294_dtp_incidents.sql
|
||
-- ДТП (dtp-stat.ru, первоисточник — открытые данные ГИБДД), Свердловская обл. (#3410).
|
||
--
|
||
-- WHY: слой ДТП нужен как радиусный "фактор безопасности" района (по образцу
|
||
-- osm_poi_ekb_local / 169_osm_poi_ekb_local.sql — та же архитектура: пустая таблица +
|
||
-- индексы на деплое, наполнение отдельным рефреш-джобом, никакого чтения внешнего
|
||
-- источника при прогоне миграций).
|
||
--
|
||
-- ИСТОЧНИК: https://dtp-stat.ru/media/opendata/sverdlovskaia-oblast.geojson.zip — открытый
|
||
-- агрегатор данных ГИБДД, без auth. Дамп заморожен (Last-Modified 26.02.2026 на момент
|
||
-- проверки 08.09.2026) — см. докстринг app/services/dtp_stat_loader.py, пустая дельта на
|
||
-- рефреше это НЕ баг, а факт источника.
|
||
--
|
||
-- ПДн (важно): properties.vehicles[].participants[] источника содержит пол/роль/нарушения
|
||
-- физлиц-участников ДТП. Эта таблица их СОЗНАТЕЛЬНО НЕ хранит — ни колонкой, ни в jsonb.
|
||
-- Загрузчик (dtp_stat_loader.py) участников/транспорт из парсинга просто не извлекает.
|
||
-- Берём только агрегаты (dead/injured count) и не-персональные атрибуты происшествия.
|
||
--
|
||
-- ИНДЕКСЫ (урок 270_houses_geog_gist_idx.sql / 134_listings_geom_geography_gist.sql): весь
|
||
-- код МЕРЫ ходит радиусными запросами через ST_DWithin(geom::geography, …) — обычный GIST
|
||
-- по geometry планировщик под такой предикат не берёт (прод-замер houses: 70.7 мс на
|
||
-- bitmap-фильтр всех строк; после функционального индекса по geography — 38 мс на listings).
|
||
-- Поэтому сразу оба индекса: geometry (на будущее/для прочих операторов) и функциональный
|
||
-- по (geom::geography) — под фактический предикат dtp_index.py.
|
||
--
|
||
-- Идемпотентно: CREATE TABLE/INDEX IF NOT EXISTS. Безопасно перезапускать.
|
||
BEGIN;
|
||
SET LOCAL lock_timeout = '5s';
|
||
|
||
CREATE TABLE IF NOT EXISTS dtp_incidents (
|
||
id bigserial PRIMARY KEY,
|
||
source_id text UNIQUE,
|
||
dtp_at timestamptz,
|
||
category text,
|
||
severity text,
|
||
dead integer,
|
||
injured integer,
|
||
address text,
|
||
light text,
|
||
weather text[],
|
||
nearby text[],
|
||
lat double precision,
|
||
lon double precision,
|
||
geom geometry(Point, 4326),
|
||
loaded_at timestamptz NOT NULL DEFAULT now()
|
||
);
|
||
|
||
COMMENT ON TABLE dtp_incidents IS
|
||
'ДТП по Свердловской обл. (dtp-stat.ru, первоисточник — открытые данные ГИБДД, #3410). '
|
||
'Пишет app/tasks/dtp_stat_refresh.py (TRUNCATE+INSERT, scheduler source=dtp_stat_refresh, '
|
||
'seed 293, enabled=false — включение вручную). Читает app/services/dtp_index.py — '
|
||
'радиусные агрегаты (число ДТП/тяжёлых/погибших/раненых) для карточки района. '
|
||
'ПДн участников (vehicles/participants: пол, роль, нарушения физлиц) осознанно НЕ '
|
||
'хранятся — ни колонкой, ни в jsonb; источник даёт их построчно на транспорт/участника, '
|
||
'загрузчик их не извлекает вовсе.';
|
||
|
||
COMMENT ON COLUMN dtp_incidents.source_id IS 'properties.id из dtp-stat GeoJSON — ключ идемпотентности (UNIQUE).';
|
||
COMMENT ON COLUMN dtp_incidents.dtp_at IS 'properties.datetime, распарсено в timestamptz.';
|
||
COMMENT ON COLUMN dtp_incidents.category IS 'properties.category — тип ДТП ("Столкновение" и т.п.).';
|
||
COMMENT ON COLUMN dtp_incidents.severity IS 'properties.severity — тяжесть ("Тяжёлый"/"Лёгкий"/…).';
|
||
COMMENT ON COLUMN dtp_incidents.dead IS 'properties.dead_count — погибшие, агрегат, без ФИО/пола участников.';
|
||
COMMENT ON COLUMN dtp_incidents.injured IS 'properties.injured_count — раненые, агрегат.';
|
||
COMMENT ON COLUMN dtp_incidents.weather IS 'properties.weather — список погодных условий на момент ДТП.';
|
||
COMMENT ON COLUMN dtp_incidents.nearby IS 'properties.nearby — список объектов УДС/притяжения рядом с местом ДТП.';
|
||
COMMENT ON COLUMN dtp_incidents.geom IS 'ST_SetSRID(ST_MakePoint(lon, lat), 4326) — строится явно в загрузчике, без триггера (как osm_poi_ekb_local).';
|
||
|
||
-- GIST по geometry — на будущее / прочие geometry-операторы.
|
||
CREATE INDEX IF NOT EXISTS dtp_incidents_geom_idx
|
||
ON dtp_incidents USING GIST (geom);
|
||
|
||
-- Функциональный GIST по (geom::geography) — под фактический предикат
|
||
-- ST_DWithin(geom::geography, …) в app/services/dtp_index.py (см. WHY выше).
|
||
CREATE INDEX IF NOT EXISTS dtp_incidents_geog_idx
|
||
ON dtp_incidents USING GIST ((geom::geography));
|
||
|
||
CREATE INDEX IF NOT EXISTS dtp_incidents_dtp_at_idx
|
||
ON dtp_incidents (dtp_at);
|
||
|
||
COMMIT;
|