- Зачем:
- STG-слой использовал legacy-имена (batch_id, load_dttm, src_created_at_ts),
тогда как ODS/DDS/DM уже работали с каноном (_load_id, _load_ts, event_ts).
Студент видел разные имена для одного понятия — это убрано.
- Что:
- переименованы колонки в 9 STG DDL: batch_id→_load_id, load_dttm→_load_ts,
src_created_at_ts→event_ts; добавлен NOT NULL для _load_id во всех таблицах.
- обновлены 9 STG Load, 9 STG DQ, 9 ODS Load, 9 ODS DQ (INSERT/SELECT/WHERE).
- обновлены DAG-файлы bookings_to_gp_stage.py и bookings_to_gp_ods.py
(встроенный SQL резолвера, комментарии; Python-идентификаторы не тронуты).
- обновлены тесты и ~15 документов (naming_conventions, PRD, db_schema,
design-docs, qa-plan, README, TESTING и др.).
- Проверка:
- grep -rn 'load_dttm\|src_created_at_ts' sql/ airflow/ tests/ — 0 совпадений.
- make test — 4 passed.
- e2e-etl: day1 прошёл полностью, day2 стартовал без ошибок.
119 lines
7.6 KiB
Markdown
119 lines
7.6 KiB
Markdown
# Унификация нейминга служебных полей в STG
|
||
|
||
## Контекст
|
||
|
||
В STG-слое используются legacy-имена служебных полей (`batch_id`, `load_dttm`, `src_created_at_ts`), а начиная с ODS — каноничные (`_load_id`, `_load_ts`, `event_ts`). Студент видит разные имена для одного понятия. Цель — привести STG к канону, убрав расхождение.
|
||
|
||
> **Breaking change (dev-only).** Это ломающее переименование колонок. Миграционный шаг (ALTER TABLE … RENAME COLUMN) не предусмотрен. DDL-файлы используют `CREATE TABLE IF NOT EXISTS`, поэтому сами по себе они не пересоздадут существующие таблицы с новыми именами колонок. План предполагает заранее пересозданную среду (например, `make down && make up`) или ручной `DROP TABLE` / `DROP SCHEMA` перед `make ddl-gp`. Обратная совместимость не обеспечивается.
|
||
|
||
## Маппинг
|
||
|
||
| Legacy (STG сейчас) | Канон (ODS/DDS/DM) |
|
||
|---|---|
|
||
| `batch_id` | `_load_id` |
|
||
| `load_dttm` | `_load_ts` |
|
||
| `src_created_at_ts` | `event_ts` |
|
||
|
||
### Оговорка про `event_ts` в snapshot-справочниках
|
||
|
||
В транзакционных STG-таблицах (bookings, tickets, flights, segments, boarding_passes) поле `src_created_at_ts` действительно хранит время события из источника — переименование в `event_ts` семантически точно.
|
||
|
||
В snapshot-справочниках (airports, airplanes, routes, seats) это поле заполняется `now()` при загрузке, т.е. по факту это ещё одно load-time, а не время события. Тем не менее мы сохраняем единое имя `event_ts` как **учебное упрощение** — ради консистентной структуры STG-таблиц. Это зафиксировано как осознанный trade-off: единообразие важнее семантической точности в справочниках. В `naming_conventions.md` нужно добавить соответствующую оговорку (раздел 4, «Time Rule»).
|
||
|
||
## Что НЕ переименовываем
|
||
|
||
- PL/pgSQL переменная `v_batch_id` — это локальная переменная, не колонка
|
||
- Python-функция `_resolve_stg_batch_id`, переменная `stg_batch_id`, task_id `resolve_stg_batch_id` — это Python/Airflow-идентификаторы
|
||
- XCom-ключи, ссылающиеся на task_id
|
||
|
||
## Порядок выполнения
|
||
|
||
### Шаг 1: STG DDL (9 файлов)
|
||
|
||
`sql/stg/{bookings,tickets,flights,segments,airports,airplanes,routes,seats,boarding_passes}_ddl.sql`
|
||
|
||
В каждом: `batch_id` → `_load_id`, `load_dttm` → `_load_ts`, `src_created_at_ts` → `event_ts`.
|
||
|
||
### Шаг 2: STG Load (9 файлов)
|
||
|
||
`sql/stg/{bookings,tickets,flights,segments,airports,airplanes,routes,seats,boarding_passes}_load.sql`
|
||
|
||
INSERT-списки, SELECT, WHERE, комментарии — те же 3 замены.
|
||
|
||
### Шаг 3: STG DQ (9 файлов)
|
||
|
||
`sql/stg/{bookings,tickets,flights,segments,airports,airplanes,routes,seats,boarding_passes}_dq.sql`
|
||
|
||
WHERE-условия (`batch_id = v_batch_id` → `_load_id = v_batch_id`), RAISE-сообщения, комментарии.
|
||
|
||
### Шаг 4: ODS Load (9 файлов)
|
||
|
||
Два подтипа — обрабатывать по-разному.
|
||
|
||
#### 4a: Транзакционные таблицы (5 файлов)
|
||
|
||
`sql/ods/{bookings,tickets,flights,segments,boarding_passes}_load.sql`
|
||
|
||
SELECT из STG: `s.batch_id` → `s._load_id`, `s.load_dttm` → `s._load_ts`, `s.src_created_at_ts` → `s.event_ts`. Убрать лишние алиасы (`s.src_created_at_ts AS event_ts` → просто `s.event_ts`).
|
||
|
||
#### 4b: Snapshot-справочники (4 файла)
|
||
|
||
`sql/ods/{airports,airplanes,routes,seats}_load.sql`
|
||
|
||
Здесь `event_ts` отсутствует в целевой ODS-таблице — менять только ссылки на STG-колонки: `s.batch_id` → `s._load_id`, `s.load_dttm` → `s._load_ts`, `s.src_created_at_ts` → `s.event_ts` (только в ORDER BY / WHERE, где они читают из STG). ODS-колонка `_load_ts` по-прежнему заполняется через `now()`, это не меняется.
|
||
|
||
### Шаг 5: ODS DQ (9 файлов)
|
||
|
||
`sql/ods/{bookings,tickets,flights,segments,airports,airplanes,routes,seats,boarding_passes}_dq.sql`
|
||
|
||
`WHERE batch_id =` → `WHERE _load_id =`, RAISE-сообщения.
|
||
|
||
### Шаг 6: DAG-файлы (2 файла)
|
||
|
||
- `airflow/dags/bookings_to_gp_stage.py` — комментарий про `batch_id`
|
||
- `airflow/dags/bookings_to_gp_ods.py` — встроенный SQL-запрос резолвера: все `batch_id` как колонка → `_load_id`, `load_dttm` → `_load_ts`. Python-имена не трогаем.
|
||
|
||
### Шаг 7: Тесты (3 файла)
|
||
|
||
- `tests/test_ods_snapshot_integration.py` — inline DDL и INSERT в тестах
|
||
- `tests/test_dags_smoke.py` — комментарии
|
||
- `tests/test_ods_sql_contract.py` — docstring
|
||
|
||
### Шаг 8: Документация (~15 файлов)
|
||
|
||
- `docs/internal/naming_conventions.md` — убрать legacy-исключение (секция 5/STG), убрать переходный маппинг (секция 6), добавить оговорку про `event_ts` в snapshot-справочниках (секция 4)
|
||
- `docs/internal/db_schema.md` — описания STG-полей
|
||
- `docs/internal/bookings_stg_design.md` — дизайн STG
|
||
- `docs/internal/bookings_ods_design.md` — маппинг STG→ODS, SQL-примеры
|
||
- `docs/internal/qa-plan.md` — SQL-запросы проверок
|
||
- `docs/internal/architecture_review.md` — архитектурные заметки
|
||
- `docs/internal/bookings_stg_code_review.md` — код-ревью
|
||
- `docs/bookings_to_gp_stage.md` — описание STG DAG, примеры полей
|
||
- `docs/bookings_to_gp_ods.md` — описание ODS DAG
|
||
- `docs/dag_execution_order.md` — порядок выполнения DAG
|
||
- `educational-tasks.md` — учебные задания
|
||
- `README.md` — SQL-примеры в README
|
||
- `TESTING.md` — чек-лист тестирования
|
||
|
||
### Шаг 9: Верификация
|
||
|
||
```bash
|
||
# 1. Проверить SQL и Python — не должно быть колонок batch_id
|
||
# (допустимы только: v_batch_id, stg_batch_id, resolve_stg_batch_id)
|
||
grep -rn 'batch_id' sql/stg/ sql/ods/ airflow/dags/ tests/ --include='*.sql' --include='*.py'
|
||
|
||
# 2. Ноль совпадений по старым именам в коде
|
||
grep -rn 'load_dttm' sql/ airflow/dags/ tests/ --include='*.sql' --include='*.py'
|
||
grep -rn 'src_created_at_ts' sql/ airflow/dags/ tests/ --include='*.sql' --include='*.py'
|
||
|
||
# 3. Проверить документацию — не должно быть старых имён как актуальных
|
||
# (допустимы упоминания в историческом контексте)
|
||
grep -rn 'batch_id\|load_dttm\|src_created_at_ts' docs/ educational-tasks.md README.md TESTING.md
|
||
|
||
# 4. Тесты и линтер
|
||
make test
|
||
make fmt && make lint
|
||
```
|
||
|
||
## Итого: ~55 файлов, ~3 механические замены в каждом
|