- Зачем:
- обнаружен конфликт между дизайном БД и планом курсового задания:
эталонный пайплайн неработоспособен на main без студенческих измерений.
- Что:
- создан docs/plans/2026-03-11_routes-to-reference.md (v4, после 3 раундов ревью).
- добавлен бэклог PXF-практикума в assignment_design.md (раздел 6).
- Проверка:
- прочитать план, убедиться в согласованности формулировок.
11 KiB
Дизайн курсового задания
Тактические решения по нарезке задания, порядку выполнения и самопроверке. Стратегию и контекст см. в PRD.md.
1. Эталонный срез: витрина sales_report
Эталоном выбрана витрина dm.sales_report и вся её цепочка вниз по слоям.
Почему sales_report:
- Покрывает SCD1 (airports, tariffs), HWM-инкремент, fact load
- Богатая денормализация — хороший образец для подражания
- Средняя сложность — не пугает, но и не тривиальна
Эталонные таблицы (даны студенту)
| Слой | Таблицы |
|---|---|
| DM | sales_report |
| DDS | fact_flight_sales, dim_airports (SCD1), dim_tariffs (SCD1), dim_calendar |
| ODS | bookings, tickets, segments, flights, boarding_passes, airports |
| STG | bookings, tickets, segments, flights, boarding_passes, airports |
Задание студенту
| Слой | Таблицы | Что нового для студента |
|---|---|---|
| STG | airplanes, seats, routes |
Практика по аналогии с эталоном |
| ODS | airplanes, seats, routes |
Практика SCD1 UPSERT по аналогии |
| DDS | dim_airplanes (SCD1), dim_passengers (SCD1), dim_routes (SCD2) |
SCD2 — ключевой вызов курсовой |
| DM | airport_traffic, monthly_overview, route_performance, passenger_loyalty |
Разная сложность (от простой к сложной) |
2. Рекомендуемый порядок выполнения
Студенту рекомендуется (но не обязательно) двигаться в таком порядке:
- STG (airplanes, seats, routes) — разминка, по аналогии
- ODS (airplanes, seats, routes) — закрепление UPSERT
- DDS dim_airplanes, dim_passengers (SCD1) — новые измерения
- DDS dim_routes (SCD2) — ключевой вызов
- DM airport_traffic — простая витрина, похожа на sales_report
- DM route_performance — TRUNCATE+INSERT, SCD2-агрегация по BK
- DM monthly_overview — двухуровневая агрегация
- DM passenger_loyalty — самая сложная, пересчёт истории
Порядок выстроен от простого к сложному. Каждый шаг опирается на опыт предыдущего.
3. SCD2: подход «рецепт без готового SQL»
Реализация dim_routes (SCD2) — ключевой вызов курсовой. Студент делает это
самостоятельно, но ТЗ содержит пошаговую подсказку:
- Алгоритм SCD2 текстом (без SQL):
- Вычисли
hashdiffпо набору атрибутов (атрибуты перечислены в ТЗ) - Найди строки, у которых
hashdiffизменился - Закрой старую версию (
valid_to = текущая_дата) - Вставь новую версию (
valid_from = текущая_дата,valid_to = NULL)
- Вычисли
- Формула hashdiff:
md5(concat_ws('|', field1, field2, ...)) - Ссылка на
naming_conventions.md(поляvalid_from,valid_to,hashdiff) - Напоминание: полуоткрытый интервал
[valid_from, valid_to) - Если застрял — ветка
solution
Самостоятельная реализация — ключ к запоминанию. SCD2 — обязательный вопрос на собеседованиях DE, и студент должен уметь объяснить его на основе собственного опыта.
4. Валидационный DAG (bookings_validate)
Отдельный DAG для самопроверки студента. Запускается вручную в Airflow UI после реализации заданий. Таски сгруппированы по слоям — студент видит, где именно проблема. Дополнительный бонус — практика чтения логов Airflow.
Примерная структура тасков
bookings_validate
├── validate_stg
│ ├── check_stg_airplanes_exists (таблица создана, >0 строк)
│ ├── check_stg_seats_exists
│ └── check_stg_routes_exists
├── validate_ods
│ ├── check_ods_airplanes_rowcount (ODS >= STG по кол-ву уникальных BK)
│ ├── check_ods_seats_rowcount
│ ├── check_ods_routes_rowcount
│ └── check_ods_no_null_pks (PK not null)
├── validate_dds
│ ├── check_dim_airplanes_exists
│ ├── check_dim_passengers_exists
│ ├── check_dim_routes_scd2 (valid_from/valid_to корректны)
│ └── check_dim_routes_no_gaps (нет «дыр» в версиях SCD2)
└── validate_dm
├── check_airport_traffic_exists
├── check_monthly_overview_exists
├── check_route_performance_exists
└── check_passenger_loyalty_exists
Реализация
PostgresOperator+ SQL-скрипты вsql/validate/- Каждый SQL-скрипт выполняет SELECT и бросает исключение (через
DO $$ ... RAISE EXCEPTION ... $$), если проверка не пройдена - Сообщения об ошибках — дружелюбные, с подсказкой что делать дальше
Ключевые проверки
- Таблицы существуют и содержат данные
- PK не содержат NULL
- SCD2:
valid_to IS NULLдля текущих версий, нет перекрытий интервалов - Кросс-слойная консистентность (row count ODS vs STG)
- DM-витрины содержат данные за загруженные дни
Активная проверка SCD2 (check_dim_routes_scd2)
Справочник bookings.routes в демо-базе статичен — маршруты не меняются
между запусками генератора. Поэтому при обычном прогоне пайплайна студент
никогда не увидит, как SCD2 закрывает старую версию и создаёт новую.
Чтобы проверить корректность реализации, таск check_dim_routes_scd2
должен быть активным (не только читать, но и тестировать загрузку):
- Сохранить текущее состояние
ods.routesиdds.dim_routes(temp-таблицы). - Вставить в
ods.routesтестовый маршрут с изменённым атрибутом (например,scheduled_time→departure_timeсдвинут на 1 час). - Вызвать студенческий SQL загрузки
dim_routes(sql/dds/dim_routes_load.sql). - Проверить результат:
- Старая версия маршрута закрыта (
valid_to IS NOT NULL). - Новая версия открыта (
valid_to IS NULL,hashdiffотличается). - Нет «дыр» между
valid_toстарой иvalid_fromновой версии.
- Старая версия маршрута закрыта (
- Откатить изменения: восстановить
ods.routesиdds.dim_routesиз сохранённых temp-таблиц.
Это единственный способ гарантировать, что SCD2 работает, без мутации
источника (что сломало бы генератор continue()).
5. Формат ТЗ от аналитика
Файл: docs/assignment/analyst_spec.md (или несколько файлов по слоям).
Для каждой таблицы-задания документ содержит:
- Имя таблицы и целевая схема (stg / ods / dds / dm)
- Описание — что хранит таблица, бизнес-смысл
- Список полей с типами и описанием
- Маппинг источников — откуда берётся каждое поле
- Бизнес-правила и фильтры (если есть)
- Тип историзации (SCD1 / SCD2 / snapshot / append)
- Гранулярность (одна строка = ?)
- Distribution key (подсказка или задание на выбор)
Формат — приближен к реальным ТЗ, которые студент встретит на работе.
6. Бэклог: идеи для будущих итераций
PXF-практикум (замена STG-заданий)
После переноса всего STG-слоя в эталон (см. docs/plans/2026-03-11_routes-to-reference.md)
студенты не практикуются в создании PXF external tables и загрузке сырых данных.
Это важный навык для DE — нужно компенсировать отдельным заданием.
Варианты:
- Новый источник данных: подключить CSV/JSON-файл (например, справочник городов или курсов валют) через PXF и загрузить в отдельную STG-таблицу
- Мини-задание «подключи внешний справочник»: студент создаёт PXF external table для существующей таблицы источника и сравнивает результат с эталонной STG
- Лабораторная работа: отдельное упражнение на создание external table + сравнение форматов (TEXT vs CUSTOM), профилей PXF, обработку типов