From ae7f909f5d2acef40573325088ec14c24144f119 Mon Sep 17 00:00:00 2001 From: Dmitry Dementev Date: Tue, 9 Dec 2025 10:39:47 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87=D0=B8=20?= =?UTF-8?q?=D0=BD=D0=B0=20ETL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/internal/bookings_stg_design.md | 126 +++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 docs/internal/bookings_stg_design.md diff --git a/docs/internal/bookings_stg_design.md b/docs/internal/bookings_stg_design.md new file mode 100644 index 0000000..21ae467 --- /dev/null +++ b/docs/internal/bookings_stg_design.md @@ -0,0 +1,126 @@ +# Дизайн STG для bookings в Greenplum (черновик) + +_Внутренний документ для учебного стенда. Перед итоговой сдачей можно объединить с основной документацией._ + +## 1. Цель и общий контур + +- Источник: Postgres в контейнере `bookings-db`, база `demo`, таблица `bookings.bookings` (см. `docs/internal/bookings_tz.md`). +- Цель: показываем путь данных от операционной БД до сырого слоя DWH в Greenplum. +- В этом документе описываем только часть `src (bookings-db) → STG (Greenplum)`. Слои ODS/DDS/DM студент проектирует сам по статье про моделирование DWH. + +Логика на уровне слоёв (по статье): + +- `src`: оперативная система (`bookings-db`, схема `bookings`). +- `stg`: сырой слой в Greenplum, максимально близкий к источнику, без бизнес‑логики. +- дальше по заданию менти можно строить `ods`/`dds`/`dm` поверх STG. + +## 2. Схема и таблицы в Greenplum + +### 2.1. Схема + +- Используем одну схему `stg` в Greenplum. +- В этой схеме будут: + - внешняя таблица PXF для чтения из `bookings-db`; + - внутренняя таблица STG для долговременного хранения «сырых» данных. + +### 2.2. Внешняя таблица (PXF) + +- Имя таблицы: `stg.bookings_ext`. +- Назначение: «окно» в исходную таблицу `bookings.bookings` в `bookings-db` через PXF (JDBC). +- Типы колонок: + - можем использовать «родные» типы из `bookings.bookings` (включая даты/числа); + - задача внешней таблицы — корректно читать данные из источника, не заниматься приведением типов. + +DDL будет добавлен в `sql/ddl_gp.sql` в блоке DDL для Greenplum (примерно по шаблону из `docs/internal/pxf_bookings.md`), с `LOCATION ('pxf://bookings.bookings?PROFILE=JDBC&SERVER=bookings-db')`. + +### 2.3. Внутренняя таблица STG + +- Имя таблицы: `stg.bookings`. +- Назначение: хранить сырые данные из источника для последующей обработки (ODS/DDS/витрины). +- Принципы моделирования: + - все бизнес‑колонки из `bookings.bookings` храним как `TEXT` (как в примерах STG из статьи); + - не делаем `UPDATE/DELETE`, только `INSERT` новых записей; + - бизнес‑колонки по названию совпадают с источником (чтобы проще было маппить). + +Технологические колонки: + +- `src_created_at_ts TIMESTAMP` — дата/время из источника, приведённая к TIMESTAMP: + - используется как опорная колонка для инкрементальной загрузки; + - заполняется из исходной даты/времени (`created_at` или аналог). +- `load_dttm TIMESTAMP NOT NULL DEFAULT now()` — когда запись была загружена в STG. +- `batch_id TEXT NOT NULL` — идентификатор «пачки» (например, `{{ ds_nodash }}` или `run_id` Airflow). +- при необходимости позже можно добавить `src_system TEXT`, если появятся другие источники. + +Колонки‑бизнес‑ключи (`booking_id` и т.п.) храним как `TEXT`. В слое DDS позже можно будет ввести суррогатные ключи и нормализовать модель под витрины. + +## 3. Инкрементальная загрузка + +### 3.1. Опорное поле для инкремента + +- Опорная колонка: `src_created_at_ts` (внутреннее имя в STG). +- Источник значения: + - берём из соответствующей колонки в `bookings.bookings` (например, `book_date`/`created_at` — будет уточнено при реализации); + - при чтении через `stg.bookings_ext` приводим к `TIMESTAMP`. + +### 3.2. Правила определения full/delta + +- При первом запуске, если таблица `stg.bookings` пуста: + - считаем режим `full` — загружаем все строки из `stg.bookings_ext`. +- При последующих запусках: + - читаем `max(src_created_at_ts)` из `stg.bookings` за все предыдущие загрузки; + - считаем, что нужно загрузить только строки, где `src_created_at_ts` больше этой максимальной метки и не позже конца текущего учебного дня. + +Таким образом, вся логика инкремента «замкнута» на один техно‑столбец `src_created_at_ts`, который студент потом сможет использовать и на следующих слоях (например, в CDC‑логике). + +## 4. DAG’и Airflow (логика на уровне задач) + +### 4.1. DAG для DDL + +- `dag_id`: `bookings_stg_ddl` (рабочее имя). +- Назначение: один раз (или при изменении схемы) создать необходимые объекты в Greenplum: + - схему `stg` (если её ещё нет); + - внешнюю таблицу `stg.bookings_ext` (PXF → `bookings-db`); + - внутреннюю таблицу `stg.bookings` с текстовыми колонками и тех.полями. +- Этот DAG не загружает данные, только подготавливает структуру. +- Вся DDL‑логика (CREATE/ALTER/DROP) сосредоточена здесь; рабочие DAG’и занимаются только DML (INSERT/SELECT). + +### 4.2. DAG для ежедневной загрузки + +- `dag_id`: `bookings_to_gp_stage` (рабочее имя). +- Основные параметры: + - `load_date` (по умолчанию `{{ ds }}`) — учебный день, за который генерим и грузим данные. + - подключения: + - `bookings_db_conn_id` — Airflow connection к `bookings-db`; + - `greenplum_conn_id` — Airflow connection к Greenplum. + +Предлагаемая последовательность задач: + +1. `generate_bookings_day` + - при необходимости создаёт таблицу `bookings.bookings` в `bookings-db` (одноразово); + - **идемпотентность**: проверяет, есть ли данные за `load_date` в `bookings.bookings`; + - если нет — генерирует данные за один учебный день (можно опираться на `make bookings-generate-day` и логику из `docs/internal/bookings_tz.md`); + - если да — ничего не делает, логирует «данные за этот день уже есть» и считается успешно выполненной. +2. `get_last_loaded_ts_from_gp` + - читает `max(src_created_at_ts)` из `stg.bookings`; + - если данных нет — возвращает `None` и режим загрузки `full`; + - результат (последняя метка и режим) передаёт через XCom. +3. `extract_and_load_increment_via_pxf` + - делает `INSERT INTO stg.bookings (...) SELECT ... FROM stg.bookings_ext WHERE src_created_at_ts > :last_ts AND src_created_at_ts <= :window_end`; + - в режиме `full` подставляет «минимальную» дату (или просто не фильтрует); + - заполняет `src_created_at_ts`, `load_dttm`, `batch_id`. +4. `check_row_counts` + - сравнивает количество строк, прочитанных из `stg.bookings_ext`, и количеством реально вставленных в `stg.bookings`; + - при расхождении падает с понятным сообщением «что посмотреть/проверить». +5. (опционально) `finish_summary` + - логирует итог: режим загрузки (full/delta), интервал `src_created_at_ts`, количество строк. + +Эта последовательность служит учебным примером для менти: от генерации «операционных» данных до инкремента в сырой слой DWH. + +## 5. Связь с остальными документами + +- `docs/internal/bookings_tz.md` — как готовится и генерируется источник `bookings-db`. +- `docs/internal/pxf_bookings.md` — детали настройки PXF и внешней таблицы для чтения из `bookings-db`. +- `sql/ddl_gp.sql` — итоговый DDL для схемы `stg` и таблиц `stg.bookings_ext` / `stg.bookings` (применяется через `make ddl-gp`). + +Дальнейшая модель DWH (слои ODS/DDS/DM, факт/измерения, SCD) должна быть спроектирована студентом по статье о моделировании данных, используя `stg.bookings` как входной слой. +