- Зачем:
- менти строит витрины DM сам, от DDL по правилу зерна до задачи в
конвейере; стенду нужны ТЗ с образцом и обратная связь по каждой
витрине (#159, резолюция #135).
- Что:
- docs/labs/: README и пять ТЗ — events_enriched_v, top_pages_daily,
session_overview, dq_errors_daily, utm_effectiveness; каждое ТЗ
называет урок, состав колонок, форму по зерну и самопроверку.
- dags/homework_check.py: ручной даг, задача на витрину, красная без
витрины или при расхождении; проверки — шесть файлов sql/dq/ с
инвариантами против DDS и ODS, без золотых констант; в dq_summary
не пишет.
- docs: dm.md называет homework_check и снимает «Остается нарезке»,
§7 и §10 мастер-спеки согласованы с лабами, dds/session.md указывает
на ТЗ, AGENTS.md пополнен правилом имен docs/labs/.
- Проверка:
- make lint; make smoke 21/21, make check-clickhouse 10/10,
make check-services 7/7.
- на свежем стенде все пять задач homework_check красные и называют
ТЗ; черновик каждой витрины по тексту ТЗ зеленит свою задачу,
после сноса — снова красная; строк от самопроверки в dq_summary нет.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8.6 KiB
Учебные задания: витрины слоя DM
Пять домашек. Стенд привозит слой DM наполовину: витрины трех сюжетов дашборда и контроль качества построены, остальные витрины строит менти. Каждое задание — самостоятельное ТЗ: что за витрина, какое у нее зерно, из чего она собирается и как проверить, что собралась верно.
Общее устройство слоя — дока DM. Она отвечает на вопросы «почему так», задание отвечает на вопрос «что сделать».
Порядок
Задания идут по нарастанию: каждое следующее опирается на то, что уже усвоено.
| № | Витрина | Чему учит |
|---|---|---|
| 1 | events_enriched_v |
слой — это контракт, а не копия данных |
| 2 | top_pages_daily |
зерно сменилось — витрина материализуется и встает в конвейер |
| 3 | session_overview |
зерно решает, на какие вопросы витрина уже не ответит |
| 4 | dq_errors_daily |
у брака свой день и свой срок жизни |
| 5 | utm_effectiveness |
declared_ в имени — предупреждение, а не украшение |
Общие правила
Они одни на все пять заданий, поэтому записаны здесь, а не повторяются в каждом ТЗ.
Читать — через _v. Публичный договор сущности DDS — представление с
суффиксом _v: dds.event_v, dds.session_v. Витрина называет только
его; физические _rep и _dist служат загрузке и обслуживанию. Соседнюю
домашку витрина источником тоже не берет: витрина слоя DM читает договор
DDS, и задания остаются независимыми. Исключение одно и оно оговорено в
задании 4: у таблиц брака публичного договора нет.
Писать — только в _dist. При записи в локальную таблицу раскладку
определяет то, какая нода случайно выполняла код, а не свойство данных.
Правило и его следствия — дока хранилища,
«Раскладка по шардам».
Форма — по зерну. Витрина, меняющая зерно источника, материализуется:
dm.<имя>_rep / _dist, донор dm.<имя>_stage_rep / _stage_dist и
публичное dm.<имя>_v с явным списком колонок. Витрина, сохраняющая зерно,
остается обычным представлением. Довод — дока DM,
«Форма: по зерну, не по цене запроса».
Ключ шардирования — твое решение. Ни одно ТЗ ключа не называет.
Правило выбора и требование к донору — дока
хранилища, «Раскладка по шардам»: донор
объявляется через AS <цель>_rep и шардируется тем же ключом, что цель,
иначе замена партиции потеряет строку на одном шарде и задвоит на другом.
Названный ключ надо уметь защитить: почему он не дает перекоса и почему
более сложный тут ничего не добавляет. Образец такой защиты —
dm.revenue_daily_dist в sql/ddl/55-dm-tables.sql.
Где лежит код. DDL домашек — свой файл sql/ddl/70-labs.sql: он
применяется после стендовых по порядку имени, и твои объекты не мешаются
со стендовыми. У агрегатов рядом со стендовыми ложатся еще три запроса —
sql/dm/<витрина>_scope.sql спрашивает у хранилища, какие дни пересобирает
запуск, _rebuild.sql собирает их в донор, _replace.sql заменяет
партицию, — и задача в
dags/dm_transform.py. У разминочного
представления нет ничего из этого: весь его код — одно CREATE VIEW.
Образец на все случаи — витрина revenue_daily: у нее есть все пять
объектов, донор, сборка, замена дневных партиций и задача в конвейере.
Списывать с нее устройство можно и нужно; списывать состав колонок — нет,
он у каждой витрины свой.
Самопроверка
Даг homework_check запускается рукой, расписания у него нет. Задача
витрины красная, пока витрины нет или счет не сходится, и зеленая, когда
собрано верно. В сводку качества конвейера dm.dq_summary он не пишет:
это инструмент лабы, а не история качества стенда.
Проверка у всех заданий устроена одинаково и золотых констант не содержит:
рядом с витриной независимым запросом собирается тот же ответ — прямо из
источника витрины, минуя ее саму. У четырех заданий источник эталона тот
же, что у витрины, dds.session_v или dds.event_v; у задания 4 это
таблицы брака ODS, потому что в DDS у брака представительства нет. Обе
стороны соединяются по деловому ключу через FULL OUTER JOIN, и считается
число строк, где стороны разошлись или одной стороны нет. Ноль — зеленый.
Полное соединение здесь обязательно: при обычном пропавший день или
пропавший ключ просто не попал бы в результат и остался бы незамечен.
Раздел «Как проверить себя» каждого ТЗ называет деловой ключ и сравниваемые
величины. Тот же прием в стендовом исполнении — даг
dq_check и запросы в sql/dq/.
Предупреждение. Запросы самой проверки лежат в sql/dq/ открыто, и
имена называют витрину и роль сверки. Проверка на инвариантах неизбежно
близка к ответу: чтобы сверить витрину, надо ее пересчитать. Прятать эти
файлы никто не станет — но открыв их до того, как задание сделано, ты
обменяешь урок на готовый SQL.
Смотреть туда стоит после своей сборки: сравнить два решения полезно,
списать одно — нет.
Уборка
Черновики и опыты за собой сносить: правило проверок стенда —
дока тестирования. Снесенная витрина обязана
снова покраснить свою задачу в homework_check — если не покраснила,
проверка ничего и не проверяла.