gisogd_permits: ключ (doc_group, doc_num) схлопывает 2243 разных документа — на проде нет 23.9% реестра #2986

Closed
opened 2026-08-20 17:01:44 +00:00 by bot-backend · 2 comments
Collaborator

Коротко

Бизнес-ключ UNIQUE (doc_group, doc_num) в gisogd_permits был выбран, чтобы склеивать один документ, приходящий из двух схем портала. Схемы пересекаются на 2 документа. Ключ при этом схлопывает 2243 разных документа, потому что docNum у ГИСОГД не уникален: разрешение и изменения к нему носят один номер.

На проде отсутствует 23.9 % реестра.

Замер 20.08.2026

Списки групп сняты с портала обеими схемами (agate_sverdregion + agate_ekbgo), раздел 13:

группа документов на портале различных key различных docNum схлопывается ключом
DocRS (РНС) 6098 6096 4305 1793
DocRV (РВЭ) 5419 5415 4969 450
DocIZ (изменения) 548 547 393 155 — и не грузится вовсе
на портале (RS+RV+IZ):  12 065 документов
в gisogd_permits:        9 182 строки   (RS 4320 + RV 4862, IZ 0)
разница:                 2 883 документа — 23.9 %

Что именно теряется — на одном номере

docNum = 66-06-06-2026, группа DocRS. Портал отдаёт два разных документа:

key 1000130002719586  «Разрешение на строительство № 66-06-06-2026 от 26.02.2026»
                      dateReg 2026-02-26
key 1000130002752293  «Изменения в разрешение на строительство №66-06-06-2026…»
                      dateReg 2026-08-04

На проде осталось одно — изменение (у него date_reg позже, а UPSERT предпочитает поздний):

RS | 66-06-06-2026 | Изменения в разрешение на строительство… | source_key 1000130002752293

Самого разрешения на строительство в наших данных нет. В §6 отчёта на его месте показывается изменение к нему.

Это не единичный случай: в gisogd_permits 598 из 4320 строк РНС (13.8 %) названы «Изменения…» — то есть в этих 598 случаях изменение вытеснило исходное разрешение.

Почему нынешний ключ не оправдан замером

Ключ решает задачу межсхемной склейки. Её масштаб:

общих docNum между схемами (DocRS):  2
общих key    между схемами (DocRS):  2

Два документа. Причём эти же два делят key — значит ключ портала склеил бы их сам, без побочного эффекта.

По всем трём группам key схлопывает ровно 7 записей (6098→6096, 5419→5415, 548→547) — это и есть настоящие межсхемные дубли, и ничего больше.

Предлагаемый ключ

UNIQUE (source_key) — идентификатор документа на портале:

  • разделяет разрешение и изменения к нему (разные key);
  • по-прежнему склеивает настоящие межсхемные дубли (у них key общий);
  • правило «при конфликте предпочитаем поздний date_reg» остаётся осмысленным ровно для этих 7 случаев.

Что для этого нужно

  1. Миграция: снять UNIQUE (doc_group, doc_num), поставить UNIQUE (source_key); расширить CHECK (doc_group IN ('RS','RV')) значением 'IZ'.
  2. gisogd66.py: GROUP_CODE += DocIZ → IZ; ON CONFLICT на новый ключ.
  3. Разовый полный прогон, чтобы вернуть недостающие 2883 документа.
  4. Проверка на проде: строк в gisogd_permits ≈ 12 065 − 7, из них с doc_group='IZ' ≈ 393.

Что изменится для пользователя

В §6 «разрешения рядом» станет больше записей, и среди них появятся «Изменения в разрешение…». Это честнее нынешнего: сейчас изменение показывается ВМЕСТО разрешения, без всякого признака подмены. Стоит ли показывать изменения отдельной строкой или сворачивать их в исходное разрешение — вопрос к продукту, но данные должны быть загружены в любом случае.

Как это нашлось

Разбирая пункт ekb_ppt_tep_parser.py:72 эпика #2464, заметил, что таблица ekb_ppt_tep пуста, а URL в сиде — заглушка на несуществующий хост gisogd.ekburg.ru (не резолвится). Пошёл искать живой портал, нашёл gisogd66.midural.ru, и при перечислении групп раздела 13 увидел третью группу DocIZ, которой нет в GROUP_CODE. Дальше цифры повели сами.

Контроль метода: заведомо рабочая комбинация razdel13/DocRS тем же curl отдаёт 200 и валидный JSON — то есть 400-е на других разделах означают отсутствие разделов, а не сломанную пробу.

## Коротко Бизнес-ключ `UNIQUE (doc_group, doc_num)` в `gisogd_permits` был выбран, чтобы склеивать один документ, приходящий из двух схем портала. Схемы пересекаются **на 2 документа**. Ключ при этом схлопывает **2243 разных документа**, потому что `docNum` у ГИСОГД не уникален: разрешение и изменения к нему носят один номер. На проде отсутствует **23.9 % реестра**. ## Замер 20.08.2026 Списки групп сняты с портала обеими схемами (`agate_sverdregion` + `agate_ekbgo`), раздел 13: | группа | документов на портале | различных `key` | различных `docNum` | схлопывается ключом | |---|---|---|---|---| | DocRS (РНС) | 6098 | 6096 | 4305 | **1793** | | DocRV (РВЭ) | 5419 | 5415 | 4969 | **450** | | DocIZ (изменения) | 548 | 547 | 393 | 155 — **и не грузится вовсе** | ``` на портале (RS+RV+IZ): 12 065 документов в gisogd_permits: 9 182 строки (RS 4320 + RV 4862, IZ 0) разница: 2 883 документа — 23.9 % ``` ## Что именно теряется — на одном номере `docNum = 66-06-06-2026`, группа DocRS. Портал отдаёт **два разных документа**: ``` key 1000130002719586 «Разрешение на строительство № 66-06-06-2026 от 26.02.2026» dateReg 2026-02-26 key 1000130002752293 «Изменения в разрешение на строительство №66-06-06-2026…» dateReg 2026-08-04 ``` На проде осталось **одно** — изменение (у него `date_reg` позже, а UPSERT предпочитает поздний): ``` RS | 66-06-06-2026 | Изменения в разрешение на строительство… | source_key 1000130002752293 ``` Самого разрешения на строительство в наших данных **нет**. В §6 отчёта на его месте показывается изменение к нему. Это не единичный случай: в `gisogd_permits` **598 из 4320 строк РНС (13.8 %)** названы «Изменения…» — то есть в этих 598 случаях изменение вытеснило исходное разрешение. ## Почему нынешний ключ не оправдан замером Ключ решает задачу межсхемной склейки. Её масштаб: ``` общих docNum между схемами (DocRS): 2 общих key между схемами (DocRS): 2 ``` **Два документа.** Причём эти же два делят `key` — значит ключ портала склеил бы их сам, без побочного эффекта. По всем трём группам `key` схлопывает ровно 7 записей (6098→6096, 5419→5415, 548→547) — это и есть настоящие межсхемные дубли, и ничего больше. ## Предлагаемый ключ `UNIQUE (source_key)` — идентификатор документа на портале: - разделяет разрешение и изменения к нему (разные `key`); - по-прежнему склеивает настоящие межсхемные дубли (у них `key` общий); - правило «при конфликте предпочитаем поздний `date_reg`» остаётся осмысленным ровно для этих 7 случаев. ## Что для этого нужно 1. Миграция: снять `UNIQUE (doc_group, doc_num)`, поставить `UNIQUE (source_key)`; расширить `CHECK (doc_group IN ('RS','RV'))` значением `'IZ'`. 2. `gisogd66.py`: `GROUP_CODE` += `DocIZ → IZ`; `ON CONFLICT` на новый ключ. 3. Разовый полный прогон, чтобы вернуть недостающие 2883 документа. 4. Проверка на проде: строк в `gisogd_permits` ≈ 12 065 − 7, из них с `doc_group='IZ'` ≈ 393. ## Что изменится для пользователя В §6 «разрешения рядом» станет больше записей, и среди них появятся «Изменения в разрешение…». Это честнее нынешнего: сейчас изменение показывается ВМЕСТО разрешения, без всякого признака подмены. Стоит ли показывать изменения отдельной строкой или сворачивать их в исходное разрешение — вопрос к продукту, но данные должны быть загружены в любом случае. ## Как это нашлось Разбирая пункт `ekb_ppt_tep_parser.py:72` эпика #2464, заметил, что таблица `ekb_ppt_tep` пуста, а URL в сиде — заглушка на несуществующий хост `gisogd.ekburg.ru` (не резолвится). Пошёл искать живой портал, нашёл `gisogd66.midural.ru`, и при перечислении групп раздела 13 увидел третью группу `DocIZ`, которой нет в `GROUP_CODE`. Дальше цифры повели сами. Контроль метода: заведомо рабочая комбинация `razdel13/DocRS` тем же curl отдаёт 200 и валидный JSON — то есть 400-е на других разделах означают отсутствие разделов, а не сломанную пробу.
Author
Collaborator

Проверено на проде

Деплой 0185889f зелёный. Миграция 192 применилась — констрейнты на проде:

chk_gisogd_permits_doc_group   CHECK (doc_group = ANY (ARRAY['RS','RV','IZ']))
uq_gisogd_permits_source_key   UNIQUE (source_key)
gisogd_permits_pkey            PRIMARY KEY (id)

Прежнего UNIQUE (doc_group, doc_num) больше нет, 'IZ' теперь допустим.

Чего проверка ещё НЕ показывает

Строки на месте: RV 4862 / RS 4320 / IZ 0 — ровно как до миграции. Это ожидаемо: миграция меняет только ключ, а недостающие 2883 документа вернёт загрузчик. Отсутствие изменений в данных сейчас ничего не доказывает — их и не должно было быть.

gisogd-permits-weekly ходит по расписанию 30 6 * * tue (вторник 06:30 МСК), последний успех — 11.08. Ближайший прогон — вторник 25.08.2026. Вручную не запускаю: это ~2900 новых карточек к стороннему госпорталу, у загрузчика своя вежливая пауза и circuit breaker, и правильный момент для этого — его собственное расписание.

Критерий с датой — 25.08.2026

После вторничного прогона на проде должно быть:

строк в gisogd_permits     ≈ 12 058   (сейчас 9 182)
doc_group='IZ'             ≈   393    (сейчас 0)
строк RS по номеру 66-06-06-2026 = 2  (сейчас 1: только «Изменения…»)

Последняя строка — самая говорящая: рядом с изменением должно появиться само разрешение на строительство, которого в данных не было.

Если 26.08 числа не сойдутся — значит дело не в ключе, и разбираться надо дальше, а не считать пункт закрытым.

## Проверено на проде Деплой `0185889f` зелёный. Миграция 192 применилась — констрейнты на проде: ``` chk_gisogd_permits_doc_group CHECK (doc_group = ANY (ARRAY['RS','RV','IZ'])) uq_gisogd_permits_source_key UNIQUE (source_key) gisogd_permits_pkey PRIMARY KEY (id) ``` Прежнего `UNIQUE (doc_group, doc_num)` больше нет, `'IZ'` теперь допустим. ## Чего проверка ещё НЕ показывает Строки на месте: `RV 4862 / RS 4320 / IZ 0` — ровно как до миграции. Это ожидаемо: миграция меняет только ключ, а недостающие 2883 документа вернёт загрузчик. Отсутствие изменений в данных сейчас **ничего не доказывает** — их и не должно было быть. `gisogd-permits-weekly` ходит по расписанию `30 6 * * tue` (вторник 06:30 МСК), последний успех — 11.08. Ближайший прогон — **вторник 25.08.2026**. Вручную не запускаю: это ~2900 новых карточек к стороннему госпорталу, у загрузчика своя вежливая пауза и circuit breaker, и правильный момент для этого — его собственное расписание. ## Критерий с датой — 25.08.2026 После вторничного прогона на проде должно быть: ``` строк в gisogd_permits ≈ 12 058 (сейчас 9 182) doc_group='IZ' ≈ 393 (сейчас 0) строк RS по номеру 66-06-06-2026 = 2 (сейчас 1: только «Изменения…») ``` Последняя строка — самая говорящая: рядом с изменением должно появиться само разрешение на строительство, которого в данных не было. Если 26.08 числа не сойдутся — значит дело не в ключе, и разбираться надо дальше, а не считать пункт закрытым.
Author
Collaborator

Исправлено — проверено на проде 28.08.

Миграция data/sql/192_gisogd_permits_key_by_source_key.sql накачена. Ограничение проверено запросом к pg_constraint:

uq_gisogd_permits_source_key | UNIQUE (source_key)

Старого уникального ключа (doc_group, doc_num) нет — он остался обычным индексом idx_gisogd_permits_group_num.

Замер, показывающий, что схлопывания больше не происходит:

значение
строк всего 11 895 (было 9182)
count(DISTINCT source_key) 11 895 — ключ реально уникален
count(DISTINCT (doc_group, doc_num)) 9563

Разница 11 895 − 9563 = 2332 документа делят пару «группа + номер» и теперь сосуществуют, а не затирают друг друга. Это и есть та потеря, ради которой заводился тикет (в теле — 2243).

Попутно: CHECK расширен до IN ('RS','RV','IZ'), и группа IZ наконец загружена — RS 6057 / RV 5309 / IZ 529 (было 0). Строк «Изменения…» 762, они теперь лежат рядом с исходными разрешениями. updated_at максимум 25.08.

Остаток, не относящийся к посылке тикета: против портальных 12 065 недостаёт около 170 документов (1,4%). Заявленные 23,9% потерь закрыты.

Закрываю.

**Исправлено — проверено на проде 28.08.** Миграция `data/sql/192_gisogd_permits_key_by_source_key.sql` накачена. Ограничение проверено запросом к `pg_constraint`: ``` uq_gisogd_permits_source_key | UNIQUE (source_key) ``` Старого уникального ключа `(doc_group, doc_num)` нет — он остался обычным индексом `idx_gisogd_permits_group_num`. Замер, показывающий, что схлопывания больше не происходит: | | значение | |---|---| | строк всего | **11 895** (было 9182) | | `count(DISTINCT source_key)` | **11 895** — ключ реально уникален | | `count(DISTINCT (doc_group, doc_num))` | 9563 | Разница 11 895 − 9563 = **2332 документа** делят пару «группа + номер» и теперь сосуществуют, а не затирают друг друга. Это и есть та потеря, ради которой заводился тикет (в теле — 2243). Попутно: `CHECK` расширен до `IN ('RS','RV','IZ')`, и группа IZ наконец загружена — RS 6057 / RV 5309 / **IZ 529** (было 0). Строк «Изменения…» 762, они теперь лежат рядом с исходными разрешениями. `updated_at` максимум 25.08. Остаток, не относящийся к посылке тикета: против портальных 12 065 недостаёт около 170 документов (1,4%). Заявленные 23,9% потерь закрыты. Закрываю.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2986
No description provided.