From 7f97654f0ad6958e5366f2c0f9775dd6003dd227 Mon Sep 17 00:00:00 2001 From: Dmitry Dementev Date: Sat, 6 Dec 2025 23:25:28 +0300 Subject: [PATCH] =?UTF-8?q?=D1=81=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B0=20bookings=20db?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 8 ++++++++ Makefile | 19 ++++++++++++++++++- README.md | 21 +++++++++++++++++---- bookings/README.md | 11 +++++++++++ bookings/generate_next_day.sql | 34 ++++++++++++++++++++++++++++++++++ docker-compose.yml | 21 +++++++++++++++++++++ 6 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 bookings/README.md create mode 100644 bookings/generate_next_day.sql diff --git a/.env.example b/.env.example index f362786..aafba2c 100644 --- a/.env.example +++ b/.env.example @@ -8,6 +8,14 @@ PG_USER=airflow PG_PASSWORD=airflow PG_DB=airflow +# Bookings demo database (Postgres) +BOOKINGS_DB_USER=bookings +BOOKINGS_DB_PASSWORD=bookings +BOOKINGS_DB_NAME=bookings +BOOKINGS_DB_PORT=5434 +# Начальная дата модельного времени для генерации демобазы +BOOKINGS_START_DATE=2017-01-01 + # Greenplum Configuration GP_USER=gpadmin GP_PASSWORD=gpadmin diff --git a/Makefile b/Makefile index bc853ed..d0d9543 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,9 @@ SHELL := /bin/bash UV := uv PYTHON_VERSION := 3.11 -.PHONY: up down airflow-init logs gp-psql ddl-gp dev-setup dev-sync dev-lock test lint fmt clean-venv +.PHONY: up down airflow-init logs gp-psql ddl-gp \ + bookings-clone-demodb bookings-init bookings-psql bookings-generate-day \ + dev-setup dev-sync dev-lock test lint fmt clean-venv up: docker compose -f docker-compose.yml up -d @@ -22,6 +24,21 @@ gp-psql: ddl-gp: docker compose -f docker-compose.yml exec greenplum bash -c "su - gpadmin -c '/usr/local/greenplum-db/bin/psql -d gpadmin -f /sql/ddl_gp.sql'" +bookings-clone-demodb: + mkdir -p bookings + test -d bookings/demodb || git clone --depth 1 https://github.com/postgrespro/demodb.git bookings/demodb + +bookings-init: bookings-clone-demodb + docker compose -f docker-compose.yml up -d bookings-db + docker compose -f docker-compose.yml exec bookings-db bash -lc 'cd /bookings/demodb && PGPASSWORD="$$POSTGRES_PASSWORD" psql -v ON_ERROR_STOP=1 -U "$$POSTGRES_USER" -d "$$POSTGRES_DB" -f install.sql' + +bookings-psql: + docker compose -f docker-compose.yml exec bookings-db bash -lc 'PGPASSWORD="$$POSTGRES_PASSWORD" psql -U "$$POSTGRES_USER" -d demo' + +bookings-generate-day: + docker compose -f docker-compose.yml up -d bookings-db + docker compose -f docker-compose.yml exec bookings-db bash -lc 'PGPASSWORD="$$POSTGRES_PASSWORD" psql -v ON_ERROR_STOP=1 -U "$$POSTGRES_USER" -d demo -v start_date="$${BOOKINGS_START_DATE:-2017-01-01}" -f /bookings/generate_next_day.sql' + dev-setup: $(UV) python install $(PYTHON_VERSION) $(UV) python pin $(PYTHON_VERSION) diff --git a/README.md b/README.md index becd8d7..9db8c05 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Учебный стенд: ETL из Postgres в Greenplum с оркестрацией в Airflow. -Добро пожаловать в учебный стенд для изучения основ Data Engineering! Этот проект поможет вам освоить ключевые инструменты современных data pipeline: **Airflow** для оркестрации, **pandas/CSV** для подготовки данных и **Greenplum** как аналитическую базу данных. +Добро пожаловать в учебный стенд для изучения основ Data Engineering! Этот проект поможет вам освоить ключевые инструменты современных data pipeline: **Airflow** для оркестрации, **pandas/CSV** для подготовки данных, **Postgres** с демобазой **bookings** как источник и **Greenplum** как аналитическую базу данных. ## 🎯 Что вы узнаете @@ -12,6 +12,7 @@ - Как загружать данные в Greenplum пакетами и избегать дублей - Как проверять качество данных в автоматизированных pipeline - Основы проектирования ETL/ELT процессов + - Как работать с демо-БД bookings в Postgres как источником для будущего DWH ## 👩‍🎓 Для студентов (10‑минутный чек‑лист) @@ -161,6 +162,7 @@ uv run black --check airflow tests - **Greenplum** — аналитическая база данных для хранения и анализа данных - **Airflow** — оркестратор workflow и задач - **Postgres** — база метаданных для Airflow +- **Postgres (bookings)** — отдельная демо-БД bookings (источник данных для будущего DWH в Greenplum) - **pandas** — библиотека для генерации и анализа данных в формате CSV ### Готовые DAG (workflow) @@ -175,6 +177,9 @@ make down # Остановить и удалить данные make airflow-init # Инициализировать Airflow make ddl-gp # Применить DDL к Greenplum make gp-psql # Подключиться к Greenplum через psql +make bookings-init # Установить демобазу bookings в Postgres +make bookings-generate-day # Добавить ещё один день данных в bookings +make bookings-psql # Подключиться к демобазе bookings (БД demo) # Проверка данных make logs # Следить за логами Airflow @@ -192,6 +197,13 @@ make logs # Следить за логами Airflow - `GP_DB` — база данных (по умолчанию: gpadmin) - `GP_PORT` — порт (по умолчанию: 5432) +### Демо-БД bookings (Postgres) +- `BOOKINGS_DB_USER` — пользователь Postgres для демобазы (по умолчанию: bookings) +- `BOOKINGS_DB_PASSWORD` — пароль пользователя (по умолчанию: bookings) +- `BOOKINGS_DB_NAME` — база данных, из которой запускается установка генератора (по умолчанию: bookings) +- `BOOKINGS_DB_PORT` — внешний порт для подключения к контейнеру bookings-db (по умолчанию: 5434) +- `BOOKINGS_START_DATE` — начальная дата модельного времени для первой генерации данных (по умолчанию: 2017-01-01) + ### CSV pipeline - `CSV_DIR` — путь к каталогу с CSV внутри контейнеров Airflow (по умолчанию: `/opt/airflow/data`) - `CSV_ROWS` — количество строк, генерируемых DAG (по умолчанию: 1000) @@ -246,13 +258,14 @@ make logs # Следить за логами Airflow ``` ├── docker-compose.yml # Описание всех сервисов ├── .env.example # Шаблон настроек -├── Makefile # Удобные команды для работы +├── Makefile # Удобные команды для работы ├── airflow/ -│ └── dags/ # Файлы workflow (DAG) +│ └── dags/ # Файлы workflow (DAG) │ ├── csv_to_greenplum.py │ └── data_quality_greenplum.py +├── bookings/ # Скрипты и вспомогательные файлы для демобазы bookings в Postgres └── sql/ - └── ddl_gp.sql # Создание таблицы в Greenplum + └── ddl_gp.sql # Создание таблицы в Greenplum ``` --- diff --git a/bookings/README.md b/bookings/README.md new file mode 100644 index 0000000..34a79b5 --- /dev/null +++ b/bookings/README.md @@ -0,0 +1,11 @@ +# Демобаза bookings в Postgres + +Этот каталог используется для работы с демобазой [bookings](https://postgrespro.ru/education/demodb), которая будет источником данных для будущего DWH в Greenplum. + +На первом этапе мы: +- поднимаем отдельный контейнер `bookings-db` с Postgres; +- устанавливаем в нём генератор демобазы `demodb` (репозиторий `postgrespro/demodb`); +- генерируем данные «день за днём» с помощью `make`‑команд. + +Основные команды см. в корневом `Makefile` (`bookings-init`, `bookings-generate-day`, `bookings-psql`) и в `README.md` проекта. + diff --git a/bookings/generate_next_day.sql b/bookings/generate_next_day.sql new file mode 100644 index 0000000..e7bb165 --- /dev/null +++ b/bookings/generate_next_day.sql @@ -0,0 +1,34 @@ +-- Генерация ещё одного дня данных в демобазе bookings. +-- Если база пуста, берём стартовую дату из параметра :start_date (формат YYYY-MM-DD). +DO $$ +DECLARE + v_max_book_date timestamptz; + v_start_date timestamptz; + v_end_date timestamptz; +BEGIN + -- Проверяем, что демобаза установлена + IF to_regclass('bookings.bookings') IS NULL THEN + RAISE EXCEPTION 'Таблица bookings.bookings не найдена. Сначала выполните make bookings-init.'; + END IF; + + -- Ищем последнюю сгенерированную дату + SELECT max(book_date) INTO v_max_book_date FROM bookings.bookings; + + IF v_max_book_date IS NULL THEN + -- База пустая: берём стартовую дату из psql-переменной + v_start_date := date_trunc('day', :'start_date'::timestamptz); + ELSE + -- Продолжаем с дня, следующего за максимальной датой + v_start_date := date_trunc('day', v_max_book_date) + interval '1 day'; + END IF; + + v_end_date := v_start_date + interval '1 day'; + + -- Первая генерация вызывает generate(), последующие — continue() + IF v_max_book_date IS NULL THEN + CALL generate(v_start_date, v_end_date, 1); + ELSE + CALL continue(v_end_date, 1); + END IF; +END $$; + diff --git a/docker-compose.yml b/docker-compose.yml index fd2f6af..3173f54 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,6 +18,26 @@ services: timeout: 5s retries: 20 + # Postgres с демо-БД bookings (источник для будущего DWH) + bookings-db: + image: postgres:16 + env_file: .env + environment: + POSTGRES_USER: ${BOOKINGS_DB_USER} + POSTGRES_PASSWORD: ${BOOKINGS_DB_PASSWORD} + POSTGRES_DB: ${BOOKINGS_DB_NAME} + ports: + - "${BOOKINGS_DB_PORT:-5434}:5432" + volumes: + - bookings_data:/var/lib/postgresql/data + # В этот каталог будет монтироваться генератор demodb + - ./bookings:/bookings:ro + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${BOOKINGS_DB_USER} -d ${BOOKINGS_DB_NAME}"] + interval: 5s + timeout: 5s + retries: 20 + greenplum: image: woblerr/greenplum:6.27.1 # based on https://github.com/woblerr/docker-greenplum # container_name: gp_single @@ -117,5 +137,6 @@ services: volumes: pgmeta: + bookings_data: greenplum_data: airflow_data: