- Зачем:
- ветка содержала устаревшие ссылки, артефакты 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/" — пустой результат.
80 lines
4.0 KiB
Markdown
80 lines
4.0 KiB
Markdown
# 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`.
|
||
|
||
## Что должно быть готово перед запуском
|
||
|
||
1) Стенд поднят:
|
||
|
||
```bash
|
||
make up
|
||
```
|
||
|
||
2) STG, ODS и DDS уже загружены:
|
||
|
||
- выполнены DAG-и `bookings_to_gp_stage`, `bookings_to_gp_ods`, `bookings_to_gp_dds`;
|
||
- DDL-объекты созданы (`bookings_dm_ddl` или `make ddl-gp`).
|
||
|
||
## Как запустить
|
||
|
||
1) Откройте Airflow UI: http://localhost:8080.
|
||
2) Если запускаете DM впервые — выполните `bookings_dm_ddl`.
|
||
3) Запустите `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
|
||
```
|
||
|
||
## Как проверить результат
|
||
|
||
```bash
|
||
make gp-psql
|
||
```
|
||
|
||
```sql
|
||
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`).
|
||
- DQ падает на `sales_report` по `boarding_rate`:
|
||
- проверьте, что DDS загрузился корректно (`dds.fact_flight_sales` непуста).
|
||
- DQ падает на `passenger_loyalty` с ошибкой FK:
|
||
- проверьте, что `dds.dim_passengers` содержит всех пассажиров из факта.
|
||
- `finish_dm_summary` не выполняется:
|
||
- одна из DQ-задач упала; найдите в логах Airflow задачу с ошибкой и исправьте.
|