- Зачем:
- ветка содержала устаревшие ссылки, артефакты CSV-пайплайна и метки «черновик»
для полностью реализованных слоёв STG→ODS→DDS→DM.
- Что:
- AGENTS.md: заменена фраза «в будущем» на перечисление реальных слоёв ODS/DDS/DM.
- TESTING.md: удалены две строки про каталог data/ (артефакт CSV-пайплайна).
- README.md: список документации заменён на кликабельные markdown-ссылки, добавлены STG и DM DAG.
- docs/README.md: добавлен DM DAG в «Быстрый путь», DM design в «Технические детали»; убраны метки «(черновик)».
- docs/internal/bookings_stg_design.md: убран заголовок «черновик», исправлены описания слоёв и DDL.
- docs/internal/PRD.md: битая ссылка на analyst_spec.md заменена текстом с пометкой TODO.
- TODO.md: ссылка на plans/ обновлена на docs/internal/bookings_db_issues.md.
- docs/bookings_to_gp_dm.md: создан новый документ по аналогии с DDS doc (5 витрин, граф, DQ, ошибки).
- plans/ и docs/chore/: каталоги удалены (планы выполнены, история сохранена в git).
- Проверка:
- make lint && make test — прошло чисто.
- grep -n "черновик|data/|в будущем|plans/" — пустой результат.
4.0 KiB
4.0 KiB
DAG bookings_to_gp_dm: dds -> dm в Greenplum
Этот DAG — учебный пример загрузки слоя DM (Data Mart / витрины) из текущего состояния DDS.
Логика: все 5 витрин загружаются параллельно, для каждой — пара load -> dq.
Что делает DAG
- Загружает витрины DM параллельно (паттерны загрузки разные — учебная демонстрация выбора стратегии):
dm.sales_report— UPSERT по датам; DQ проверяет только строки текущегоrun_id(_load_id);dm.route_performance— Full Rebuild (TRUNCATE + INSERT): таблица маленькая, дельту считать дороже;dm.passenger_loyalty— инкрементальный UPSERT по «затронутым ключам» (HWM по_load_ts): пересчитываем агрегаты только для пассажиров с новыми фактами;dm.airport_traffic— инкрементальный UPSERT по датам (HWM по_load_ts);dm.monthly_overview— инкрементальный UPSERT по месяцам (HWM по_load_ts).
- Для каждой витрины выполняет пару задач
load -> dq.
Что должно быть готово перед запуском
- Стенд поднят:
make up
- STG, ODS и DDS уже загружены:
- выполнены DAG-и
bookings_to_gp_stage,bookings_to_gp_ods,bookings_to_gp_dds; - DDL-объекты созданы (
bookings_dm_ddlилиmake ddl-gp).
Как запустить
- Откройте Airflow UI: http://localhost:8080.
- Если запускаете DM впервые — выполните
bookings_dm_ddl. - Запустите
bookings_to_gp_dm.
Граф зависимостей
Все 5 веток запускаются параллельно от start_dm, затем сходятся в finish_dm_summary:
start_dm
├── load_dm_sales_report -> dq_dm_sales_report -> finish_dm_summary
├── load_dm_route_performance -> dq_dm_route_performance -> finish_dm_summary
├── load_dm_passenger_loyalty -> dq_dm_passenger_loyalty -> finish_dm_summary
├── load_dm_airport_traffic -> dq_dm_airport_traffic -> finish_dm_summary
└── load_dm_monthly_overview -> dq_dm_monthly_overview -> finish_dm_summary
Как проверить результат
make gp-psql
SELECT COUNT(*) FROM dm.sales_report;
SELECT COUNT(*) FROM dm.route_performance;
SELECT COUNT(*) FROM dm.passenger_loyalty;
SELECT COUNT(*) FROM dm.airport_traffic;
SELECT COUNT(*) FROM dm.monthly_overview;
-- Проверка инварианта sales_report: посаженных не больше, чем продано
SELECT COUNT(*) FROM dm.sales_report WHERE tickets_sold < passengers_boarded;
-- Проверка route_performance: нет дублей по бизнес-ключу
SELECT route_bk, COUNT(*) FROM dm.route_performance GROUP BY route_bk HAVING COUNT(*) > 1;
Ожидаемо: все витрины непусты, инварианты соблюдены, дублей нет.
Типичные ошибки
relation "dm..." does not exist:- не применён DM DDL (
bookings_dm_ddlилиmake ddl-gp).
- не применён DM DDL (
- DQ падает на
sales_reportпоboarding_rate:- проверьте, что DDS загрузился корректно (
dds.fact_flight_salesнепуста).
- проверьте, что DDS загрузился корректно (
- DQ падает на
passenger_loyaltyс ошибкой FK:- проверьте, что
dds.dim_passengersсодержит всех пассажиров из факта.
- проверьте, что
finish_dm_summaryне выполняется:- одна из DQ-задач упала; найдите в логах Airflow задачу с ошибкой и исправьте.