Files
clickstream-data-platform/docs/labs/5-1-order-checks.md
T
ddadmin 596bcba01e docs(labs): разделено задание по заказам на три шага
- Зачем:
  - одно длинное ТЗ заставляло одновременно держать в голове три самостоятельных опыта и их очистку.
- Что:
  - проверки, разбор ODS и сборка DDS разнесены по трем последовательным заданиям.
  - уточнены границы учебной реализации, место диагностики и выбор закрытого дня.
  - оглавление ступени 5 дополнено ссылками на все три задания.
- Проверка:
  - проверены ссылки, пробная пачка jq, кластерные мутации и отсутствие ошибок пробелов в diff.
2026-09-06 16:25:04 -04:00

9.5 KiB
Raw Blame History

Сначала сторож, потом ломай: заказы

Чему учит: до рискованного изменения задавать проверке явный договор и испытывать его управляемой ошибкой.

Сначала прочитать

Посмотрите также на устройство одной проверки в sql/dq/ и на ее включение в dq_check. Готового ответа для двух проверок из этого задания в репозитории нет.

Граница задания

Добавьте два сторожа:

  • sql/dq/order_items_total.sql проверяет сумму позиций заказа;
  • sql/dq/orders_vs_ods.sql сверяет DDS с его источником;
  • dags/dq_check.py запускает обе проверки, публикует их строки в dm.dq_summary и создает для них отдельные задачи.

На этом шаге не меняйте разбор ODS и сборку DDS. Даги, DDL, таблицы-доноры, Kafka и службы остаются несущей частью упражнения.

Перед опытами остановите автоматическое движение мира: поставьте world_live на паузу и дождитесь завершения активных прогонов. До чистой точки остановки не запускайте руками world_next_day, world_live_day, world_initialize и world_recreate. Это условие стабильного модельного времени: одной паузы world_live для него мало.

Два договора качества

Обе проверки следуют договору dq_check: запрос возвращает по одной строке на день с колонками data_date, reference_rows, actual_rows, failed_rows, diagnostics. Даг сохраняет в dm.dq_summary только счетчики, статус и координаты запуска. Ограниченные примеры из diagnostics ищите в журнале упавшей задачи Airflow. Ограничьте их тем же малым числом, что и существующие запросы в sql/dq/.

Сумма позиций

Имя проверки - order_items_total. Для каждого заказа из dds.order_v посчитайте сумму item_price * item_quantity и сравните ее с items_total. reference_rows считает ключи со стороны items_total, actual_rows - ключи со стороны вычисленной суммы, а failed_rows - несовпавшие значения. В исправном наборе первые два счетчика равны по построению; сам инвариант выражен через failed_rows. Для диагностики достаточно order_id, ожидаемой суммы и суммы позиций.

Проверка относится к типизированному разбору массива items на границе ODS -> DDS. Скидка, доставка и равенство total в этот договор не входят.

DDS против ODS

Имя проверки - orders_vs_ods. Источник модели DDS здесь - текущее состояние ods.order_v. Внутреннее состояние генератора в этот договор не входит. Одним запросом соберите обе стороны на зерне дня заказа и сравните:

  • число заказов;
  • максимальный updated_at.

День ODS вычисляется в Europe/Samara, как order_date в DDS. Область проверки - объединение дней обеих сторон, включая день, который полностью пропал из одного слоя. Перед сравнением приведите времена к одному часовому поясу. reference_rows - число заказов ODS, actual_rows - число заказов DDS, а failed_rows равен единице для дня, где расходится хотя бы одно значение.

Обе стороны распределены по order_id. Дневные агрегаты соедините через GLOBAL FULL OUTER JOIN с join_use_nulls = 1, как в существующих сверках.

Если разбор ODS и сборка DDS одинаково потеряют строку, слои останутся равны по этой проверке. Общая потеря при разборе проявится в отдельном балансе по _load_id из следующего задания.

Получите красный и зеленый результаты

Сначала запустите dq_check на нетронутых данных. Обе новые задачи должны завершиться успешно, а в dm.dq_summary_v у обоих имен не должно быть нарушенных дней.

Выберите оплаченный заказ из последнего слепка с непустым массивом позиций и сохраните его order_id и order_date. Подключитесь к первой ноде из DBeaver по инструкции из README под пользователем etl. Прибавьте одну копейку к items_total этого заказа в локальной таблице dds.order_rep на всем кластере:

ALTER TABLE dds.order_rep ON CLUSTER clickstream_cluster
UPDATE items_total = items_total + toDecimal64(0.01, 2)
WHERE order_id = '<order_id>'
SETTINGS mutations_sync = 2;

Затем запустите только dq_check. Задача order_items_total должна завершиться ошибкой, а ее журнал - назвать выбранный заказ. purchase_vs_orders_vs_dds тоже даст красный результат: сохраненная витрина содержит прежний items_total.

Запустите etl_pipeline. Текущее окно заказов будет заново собрано из ODS, и исходная строка вернется в DDS. Повторный dq_check должен дать зеленый результат для нового сторожа.

Теперь удалите тот же заказ из dds.order_rep на всем кластере:

ALTER TABLE dds.order_rep ON CLUSTER clickstream_cluster
DELETE WHERE order_id = '<order_id>'
SETTINGS mutations_sync = 2;

До восстановления снова запустите только dq_check. Красный результат нужен для orders_vs_ods, purchase_vs_orders_vs_dds и revenue_daily_vs_dds на дне оплаченного заказа. Затем запустите etl_pipeline и повторите проверку. Если orders_vs_ods не обнаружил удаление, исправьте запрос до следующего задания.

Как проверить себя

В dm.dq_summary_v должны быть зелены обе новые и пять прежних проверок:

SELECT check_name, sum(failed_rows) AS failed_rows, groupUniqArray(status)
FROM dm.dq_summary_v
GROUP BY check_name
ORDER BY check_name;

Проверка суммы должна охватывать каждый день dds.order_v. Сверка слоев должна охватывать объединение дней ODS и DDS, включая дни только одной стороны.

Когда можно остановиться

После двух восстановлений выбранный заказ снова совпадает с ODS. Все семь проверок дают зеленый результат. В таком состоянии можно закончить работу или перейти к разбору заказов, оставив модельное время на паузе.

Приемка

  • две новые проверки встроены в dq_check и публикуют дневные строки по принятому договору;
  • каждая проверка дала красный результат на своей управляемой ошибке;
  • журналы упавших задач содержали ограниченную диагностику;
  • etl_pipeline восстановил обе измененные строки DDS;
  • order_items_total, orders_vs_ods и пять прежних DQ зелены;
  • SQL разбора ODS и сборки DDS на этом шаге не менялся.