feat(dq): добавлен контроль качества конвейера

- Зачем:
  - конвейеру нужна публикуемая сводка текущего качества с красным завершением при нарушении договоров.
- Что:
  - добавлены DDL, публичное представление и пять сверок на естественном деловом зерне.
  - даг dq_check встроен после DM и публикует полные дневные партиции до именованных утверждений.
  - параллелизм DDS, DM и DQ приведён к измеренному лимиту памяти планировщика.
- Проверка:
  - make lint; make config-test; make rebuild-storage.
  - make smoke; make check-clickhouse; make check-services.
  - три семейства проверок покрашены искусственными расхождениями и восстановлены повторным полным прогоном.
This commit is contained in:
ddadmin committed 2026-08-27 07:55:28 -04:00
1 parent 4e60aafc31
commit 26b2e5fea1
17 files changed
+753 -38

No files matched your search

+51 -26
View File
@@ -149,31 +149,58 @@ Distributed-таблица вернула бы каждый непарный з
## `dm.dq_summary`
Зерно — «день данных × проверка»: строка отвечает, каково качество дня
сейчас, а не сколько раз его проверяли, — история прогонов и так живёт в
Airflow. Партиция — день данных; прогон звена DQ заменяет партиции
проверенных дней через `REPLACE PARTITION`. Обещанный спекой перевод с
`TRUNCATE+INSERT` выполняется той же механикой замены, что и у витрин, —
ничего отдельного учить не надо.
Зерно публичного `dm.dq_summary_v` — «день данных × атомарная проверка».
Строка отвечает, каково качество дня сейчас; историю запусков хранит Airflow.
Партиция совпадает с днём данных и заменяется через `REPLACE PARTITION`.
## Будущее звено DQ конвейера
Деловые колонки сводки:
Встанет в `etl_pipeline` после DM ([конвейер](etl.md)) и проверит только
объекты стенда:
- `data_date` — проверяемый день;
- `check_name` — устойчивое имя инварианта;
- `reference_rows` — число деловых ключей на эталонной стороне;
- `actual_rows` — число деловых ключей в проверяемом объекте;
- `failed_rows` — число отсутствующих или различающихся ключей;
- `status` — `pass` при нуле нарушений, иначе `fail`.
- счётная сверка сессий с эталоном `VisitID` — кука × день, эталон читается
из `ods.event_v` ([модель сессии](dds/session.md));
- счётчики классов расхождений против описи мира — по дням с закрытым
окном. Проверка техническая, не урок DQ: её оракул — опись генератора,
а у настоящего магазина оракула нет. Обещание узкое и честное: до
витрин доехал тот мир, который родился, — одна растяжка через весь
путь вместо сторожей на каждом шаге. Верно ли сам мир рождён, она
не видит: опись считает тот же генератор;
- счётные сверки витрин стенда с их DDS-источниками.
Служебные `_load_id` и `_load_ts` называют собравший запуск. Представление
перечисляет колонки явно. Порогов и промежуточного состояния нет.
Результаты ложатся в `dm.dq_summary`. Звено — не только сторож конвейера,
но и экспонат: менти видит, как контроль качества устроен в бою — по
расписанию, с историей, рядом с трансформациями.
## Звено DQ конвейера
Даг `dq_check` стоит в `etl_pipeline` после `dm_transform` и проверяет пять
атомарных договоров:
- `sessions_vs_reference`: ключ — `client_id` внутри дня, эталон —
`uniqExact(VisitID)` из `ods.event_v`, объект — число строк
`dds.session_v`;
- `classes_vs_inventory`: ключ — `mismatch_class`, эталон — счётчик из
`orders` в описи мира, объект — число заказов класса в
`dm.purchase_vs_orders_v`. Проверяются `match`, `cancelled` и
`amount_delta` только для покрытых описью закрытых дней;
- `revenue_daily_vs_dds`: ключ — `product_category` внутри дня. Сравниваются
`orders`, `units`, `revenue` и `aov` с прямым агрегатом `dds.order_v`;
- `purchase_vs_orders_vs_dds`: ключ — `order_id` внутри дня. Все деловые
поля сверки сравниваются с независимой сборкой из `dds.event_v` и
`dds.order_v`;
- `daily_traffic_vs_dds`: ключ — день. `visitors` и `known_users`
сравниваются с прямыми агрегатами `dds.session_v` и
`dds.identity_map_v`.
Область каждой проверки выводится из объединения сторон. Полностью потерянный
день или ключ поэтому не исчезает из результата. Разные ошибки тоже не могут
скомпенсировать друг друга общим итогом: `failed_rows` считается после
сопоставления деловых ключей.
`classes_vs_inventory` — техническая растяжка пути от генератора до DM. Она
подтверждает, что до витрины доехал записанный в описи мир, но не проверяет
сам генератор: у настоящего магазина такого оракула нет.
Пять сборок пишут в общий донор. Только после их успеха даг заменяет все
проверенные дневные партиции, затем именованные задачи читают опубликованную
сводку и падают при `failed_rows > 0`. Расхождение успевает сохраниться до
красного завершения, а ошибка сборки не затирает прежний результат. Красная
задача печатает не больше двадцати нарушенных ключей со значениями сторон;
полный список воспроизводится запросом проверки.
## Даг самопроверки
@@ -188,12 +215,10 @@ Airflow. Партиция — день данных; прогон звена DQ
валидационный даг с группами проверок по слоям давал менти обратную связь
по каждому шагу домашки, не трогая рабочий конвейер.
## Остаётся нарезке
## Остается нарезке
- Имена звена DQ и дага самопроверки.
- Ключи шардирования остальных материализованных витрин — вместе с их
DDL; правило партиции-донора — в [доке хранилища](storage.md).
- Тексты учебных заданий и точный список проверок обоих контуров.
- Имя и состав дага самопроверки домашних заданий.
- Тексты учебных заданий и точный список проверок учебного контура.
## Отклонённые варианты