Files
airflow-greenplum/docs/internal/PRD.md
T
ddadmin d77da5686c docs(internal): добавлена первая версия PRD для DWH-стенда
- Зачем:
  - необходим единый документ с требованиями для разработки ETL-процессов.
- Что:
  - создан файл docs/internal/PRD.md с описанием архитектуры, требований к данным и сроков.
- Проверка:
  - просмотр файла docs/internal/PRD.md.
2026-03-08 18:29:04 +03:00

23 KiB
Raw Blame History

PRD: Greenplum Bookings DWH

Курсовая работа для курса DE Roadmap. Статус: ЧЕРНОВИК v0.1 | Дата: 2026-03-08


1. Видение продукта

Greenplum Bookings DWH — учебный стенд, на котором студент самостоятельно строит end-to-end ETL-пайплайн: от базы-источника до аналитических витрин.

Стенд имитирует реальную рабочую задачу Data-инженера:

  • Есть «боевая» система-источник (bookings-db), в которой каждый день появляются новые данные — как в жизни, без ограниченного объёма.
  • Есть DWH на Greenplum с классическими слоями (STG → ODS → DDS → DM).
  • Есть Airflow, оркестрирующий загрузку.
  • Есть ТЗ от «аналитика» с описанием ожидаемых таблиц и маппингов.

Студент получает частично реализованный пайплайн (эталонный вертикальный срез) и дореализует остальное по ТЗ — SQL-скрипты и таски в DAG.

Почему именно bookings?

Домен бронирования авиабилетов выбран не ради предметной области, а благодаря генератору данных: каждый вызов make bookings-generate-day создаёт новый день с реалистичным объёмом. Это даёт бесконечный поток инкрементальных данных — как в настоящей production-системе.


2. Целевая аудитория и пререквизиты

Кто: студенты курса DE Roadmap, дошедшие до раздела «Курсовая работа».

Что уже умеют (к моменту старта):

  • Git: ветки, PR, merge, GitFlow
  • SQL: JOIN, CTE, оконные функции, планы запросов, моделирование (3NF, звезда, SCD)
  • Python: скрипты, pandas, базовое ООП
  • Docker: запуск контейнеров, логи, docker-compose
  • Airflow: понятие DAG, операторы, зависимости, UI, логи
  • Greenplum: распределение по сегментам, skew, EXPLAIN, отличие от Postgres

Уровень: уверенный джун, готовящийся к первым собеседованиям.


3. Учебные результаты (Learning Outcomes)

После выполнения курсовой студент умеет:

  1. Проектировать и реализовывать ETL-пайплайн по слоям DWH (STG → ODS → DDS → DM) на реальном стеке Airflow + Greenplum.
  2. Читать ТЗ от аналитика (маппинги, описания таблиц) и превращать его в работающий SQL + DAG.
  3. Писать идемпотентные загрузки с инкрементальностью (HWM, batch_id, delete+insert), понимая, почему в Greenplum не используется MERGE.
  4. Реализовывать SCD1/SCD2 и объяснять, когда что применяется.
  5. Настраивать и проверять Data Quality — понимает, зачем DQ-проверки и как их встроить в пайплайн.
  6. Работать с Greenplum как с MPP: выбирать distribution key, понимать heap vs AO, читать планы запросов.
  7. Оформить проект как портфолио — репозиторий пригоден для упаковки в резюме как реальный опыт работы с Airflow и Greenplum.

4. Скоуп

В скоупе (In Scope)

Компонент Описание
Источник данных bookings-db (Postgres) с генератором дней
DWH Greenplum, 4 слоя: STG, ODS, DDS, DM
Оркестрация Apache Airflow (PostgresOperator + SQL-файлы)
Федеративный доступ PXF (чтение из Postgres в Greenplum)
Инфраструктура Docker Compose (полный стенд в одной команде)
Data Quality DQ-проверки, встроенные в DAG
Документация README, ТЗ, design docs, naming conventions

Вне скоупа (Out of Scope)

Что Почему
Kafka / стриминг Отдельный стенд в курсе
BI-инструменты Фокус на ETL, не на визуализации
CI/CD Избыточно для курсовой
Spark / Trino / dbt Отдельные стенды в курсе
Второй источник Усложнение без пропорциональной учебной ценности
CSV-пайплайн Вынести в airflow-manual
Облачная инфраструктура Всё локально, через Docker

5. Архитектура стенда

Сервисы (Docker Compose)

bookings-db (Postgres 16) ──PXF──> Greenplum 6.27
                                      ├── stg.*    (стейджинг)
                                      ├── ods.*    (операционное хранилище)
                                      ├── dds.*    (детальное хранилище)
                                      └── dm.*     (витрины)

pgmeta (Postgres 16) ─────────────> Airflow (webserver + scheduler)

Слои DWH

Слой Назначение Паттерн загрузки Кол-во таблиц
STG Зеркало источника TRUNCATE + INSERT (batch) 9
ODS Нормализованное хранилище SCD1 UPSERT 9
DDS Измерения + факты (Kimball) SCD1/SCD2 + fact load 7 (6D + 1F)
DM Аналитические витрины HWM-инкремент 5

Сущности

STG / ODS DDS DM
bookings dim_airports airport_traffic
tickets dim_airplanes monthly_overview
airports dim_passengers passenger_loyalty
airplanes dim_routes (SCD2) route_performance
routes dim_calendar sales_report
seats dim_tariffs
flights fact_flight_sales
segments
boarding_passes

6. Педагогическая модель

Принцип: «Эталонный срез + ТЗ»

Студент получает репозиторий, в котором:

  1. Эталонный вертикальный срез — полностью реализованная цепочка для одной витрины DM и всех её источников вниз по слоям (STG → ODS → DDS → DM). Это — образец, на который студент ориентируется.

  2. ТЗ от аналитика — Markdown-документ с описанием остальных таблиц: маппинги полей, бизнес-правила, ожидаемая гранулярность, тип SCD.

  3. Частично готовый DAG — Python-файлы DAG с реализованными тасками эталонного среза. Студент добавляет свои таски по аналогии.

  4. DQ-проверки — готовые проверки, которые студент запускает для самоконтроля.

Что делает студент

  • Пишет DDL для назначенных таблиц (*_ddl.sql)
  • Пишет SQL-загрузки (*_load.sql)
  • При необходимости пишет DQ-проверки (*_dq.sql)
  • Добавляет таски в существующий DAG
  • Проверяет результат через DQ и запросы в Greenplum

Что студент НЕ делает

  • Не поднимает инфраструктуру с нуля (Docker Compose дан)
  • Не пишет DAG с нуля (шаблон дан)
  • Не настраивает Airflow Connections (преднастроены)
  • Не работает с PXF-конфигурацией (настроен)

Выбор эталонного среза

Эталонный срез: витрина 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 Разная сложность (от простой к сложной)

Рекомендуемый порядок выполнения для студента:

  1. STG (airplanes, seats, routes) — разминка, по аналогии
  2. ODS (airplanes, seats, routes) — закрепление UPSERT
  3. DDS dim_airplanes, dim_passengers (SCD1) — новые измерения
  4. DDS dim_routes (SCD2) — ключевой вызов
  5. DM airport_traffic — простая витрина, похожа на sales_report
  6. DM route_performance — TRUNCATE+INSERT, SCD2-агрегация по BK
  7. DM monthly_overview — двухуровневая агрегация
  8. DM passenger_loyalty — самая сложная, пересчёт истории

SCD2 в задании: подход «рецепт без готового SQL»

Реализация dim_routes (SCD2) — ключевой вызов курсовой. Студент делает это самостоятельно, но ТЗ содержит пошаговую подсказку:

  1. Алгоритм SCD2 текстом (без SQL):
    • Вычисли hashdiff по набору атрибутов (атрибуты перечислены в ТЗ)
    • Найди строки, у которых hashdiff изменился
    • Закрой старую версию (valid_to = текущая_дата)
    • Вставь новую версию (valid_from = текущая_дата, valid_to = NULL)
  2. Формула hashdiff: md5(concat_ws('|', field1, field2, ...))
  3. Ссылка на naming_conventions.md (поля valid_from, valid_to, hashdiff)
  4. Напоминание: полуоткрытый интервал [valid_from, valid_to)
  5. Если застрял — ветка solution

Самостоятельная реализация — ключ к запоминанию. SCD2 — обязательный вопрос на собеседованиях DE, и студент должен уметь объяснить его на основе собственного опыта.


6.1. Валидационный DAG (bookings_validate)

Отдельный DAG для самопроверки студента. Запускается вручную в Airflow UI после реализации заданий. Таски сгруппированы по слоям — студент видит, где именно проблема.

Примерная структура тасков:

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-витрины содержат данные за загруженные дни

7. Формат ТЗ от аналитика

Файл: docs/assignment/analyst_spec.md (или несколько файлов по слоям).

Для каждой таблицы-задания документ содержит:

  • Имя таблицы и целевая схема (stg / ods / dds / dm)
  • Описание — что хранит таблица, бизнес-смысл
  • Список полей с типами и описанием
  • Маппинг источников — откуда берётся каждое поле
  • Бизнес-правила и фильтры (если есть)
  • Тип историзации (SCD1 / SCD2 / snapshot / append)
  • Гранулярность (одна строка = ?)
  • Distribution key (подсказка или задание на выбор)

Формат — приближен к реальным ТЗ, которые студент встретит на работе.


8. Ветки и workflow

main (стартовое состояние)
  ├── Эталонный срез: реализованные таблицы + DAG
  ├── ТЗ от аналитика
  ├── Инфраструктура (Docker, Make, PXF)
  ├── Заглушки / TODO-маркеры для студенческих заданий
  └── DQ-проверки для самоконтроля

solution (полное решение)
  └── Все таблицы реализованы — эталон для самопроверки
      и подсказка, если студент застрял

Workflow студента

  1. Форкает репозиторий
  2. Читает README и ТЗ
  3. make up — поднимает стенд
  4. make bookings-init — инициализирует источник
  5. Запускает DDL-DAG'и (эталонные таблицы создаются)
  6. Запускает ETL-DAG'и — эталонный срез работает
  7. Реализует задания из ТЗ (SQL + таски в DAG)
  8. Проверяет себя через DQ
  9. make bookings-generate-day — генерирует новый день, проверяет инкрементальность
  10. Защищает работу перед ментором

9. Критерии приёмки курсовой

Для студента (самопроверка)

  • Стенд поднимается (make up) без ошибок
  • Все DAG'и проходят без failed-тасков
  • Данные доезжают от STG до DM
  • DQ-проверки проходят на всех реализованных таблицах
  • После make bookings-generate-day + повторного запуска DAG данные корректно доливаются (инкрементальность работает)

Для ментора (ревью + защита)

  • Код соответствует naming conventions (docs/internal/naming_conventions.md)
  • SQL идемпотентен (повторный запуск не ломает данные)
  • Distribution keys выбраны осмысленно
  • Студент может объяснить: почему delete+insert, а не MERGE; разницу SCD1/SCD2; что такое HWM; как работает batch_id
  • Код оформлен для портфолио (чистый Git-history, README)

10. Ограничения и риски

Риск / ограничение Митигация
Стенд тяжёлый (~8-16 GB RAM) Указать минимальные требования; не утяжелять
bookings-db генерирует данные медленно Не добавлять нагрузку; задокументировать ожидание
Студент может застрять надолго Ветка solution как подсказка; еженедельные встречи
Greenplum 6.x — устаревающая версия Для учебных целей достаточно; паттерны переносимы
PXF нестабилен при холодном старте Задокументировано в README; healthcheck настроен

Требования к машине студента

  • 2-4 CPU, 8-16 GB RAM, 25-40 GB диска
  • Linux / WSL2 / macOS
  • Docker + Docker Compose

11. Таймлайн

Когда Что
Ближайшие 2-3 нед. Первый студент может подойти к курсовой
До этого момента Подготовить: ТЗ, стартовое состояние main, ветку solution

12. Открытые вопросы (TODO)

  1. Выбор эталонного срезаРЕШЕНО. Эталон: sales_report и её цепочка. Задание: остальные 4 витрины + 3 STG/ODS + 3 DDS-измерения. SCD2 (dim_routes) — задание с подсказками в ТЗ. (Раздел 6)

  2. Формат DQ для самоконтроляРЕШЕНО. Отдельный валидационный DAG (bookings_validate.py). Под капотом — SQL-проверки. Студент запускает DAG в Airflow UI и видит красные/зелёные таски по слоям. Дополнительный бонус — практика чтения логов Airflow. (см. Раздел 6.1 ниже)

  3. Вынос CSV-пайплайна — перенести csv_to_greenplum.py, csv_to_greenplum_dq.py, ddl_greenplum_base.py, helpers/greenplum.py, sql/base/orders_ddl.sql и связанные тесты в репозиторий airflow-manual. Решение принято, нужно выполнить.

  4. Подготовка main — какие изменения внести в main для стартового состояния (убрать лишние реализации, добавить TODO-маркеры)?

  5. Название — рабочее: «Greenplum Bookings DWH». Финализировать.