18 KiB
Восстановите прием справочника из источника
Хранилище получает справочник аэропортов из Postgres. Названия и другие атрибуты в источнике могут меняться, поэтому загрузка должна сохранять состояние справочника на момент приема данных.
Вы разберете готовый участок airports и напишете его заново: создадите
внешнюю таблицу PXF и загрузку полного снимка в STG. Затем испытаете ее
на повторном запуске и изменении источника. Полученный снимок понадобится
следующему слою — ODS.
Задача
Ваш участок на карте:
bookings.airports_data → stg.airports_ext → stg.airports.
| Что написать | Где |
|---|---|
DDL внешней таблицы stg.airports_ext |
airports_ddl.sql |
Загрузку полного снимка во внутреннюю stg.airports |
airports_load.sql |
Внутренняя таблица, JDBC-сервер PXF, DAG и проверки качества уже готовы. Рядом есть пример для другого справочника: DDL airplanes и его загрузка. Используйте его, учитывая состав полей и ключ аэропорта.
Требования к вашей загрузке:
- Источник —
bookings.airports_dataв базеdemo, ключ —airport_code. - Все шесть полей (
airport_code,airport_name,city,country,coordinates,timezone) попадают в STG без потерь и преобразований. Внешняя и внутренняя таблицы используют TEXT; JSON и координаты пока хранятся как текст. - Строки одного снимка получают
_load_id = '{{ run_id }}',_load_ts = now()иevent_ts = now(). Точного времени изменения аэропорта в источнике нет, поэтомуevent_ts— время получения снимка. - Новый запуск сохраняет новый полный снимок, оставляя предыдущие. Повторное выполнение загрузки в том же запуске на неизменном источнике не меняет бизнес-данные и не создает дубли ключей внутри снимка.
Подготовка
Нужен свой стенд после быстрого старта и знакомства с моделью.
Во время работы не запускайте другие загрузки: они могут изменить данные
посреди опыта. Если запущен bookings_validate, дождитесь его завершения.
Сначала освободите участок для своей реализации. Команды ниже удаляют
внешнюю таблицу и всю историю только stg.airports. Это нужно, чтобы
данные быстрого старта не скрыли отсутствие вашей загрузки.
Подготовка файлов и таблиц
Сохраните свои SQL-файлы в Git или отдельной копии. В airports_ddl.sql
удалите блок от DROP EXTERNAL TABLE до конца CREATE EXTERNAL TABLE;
DDL схемы и внутренней таблицы оставьте. Содержимое airports_load.sql
замените на SELECT 1;. DAG и DQ менять не нужно.
В Greenplum (make gp-psql):
DROP EXTERNAL TABLE IF EXISTS stg.airports_ext;
TRUNCATE TABLE stg.airports;
SELECT COUNT(*) FROM stg.airports; -- 0
Остальные справочники и текущий ODS сохраняются. Пока участок не восстановлен, ODS запускать не нужно.
Соберите загрузку
Начните с внешней таблицы. Добейтесь, чтобы запрос к stg.airports_ext
возвращал те же поля и значения, что запрос к bookings.airports_data
в Postgres. Для начала достаточно рассмотреть несколько аэропортов.
Ориентиры для PXF и применение DDL
В LOCATION укажите таблицу источника, PROFILE=JDBC и SERVER=bookings-db.
SERVER — имя готового каталога конфигурации PXF.
Формат чтения — FORMAT 'CUSTOM' (formatter='pxfwritable_import').
Логин и пароль в DDL не нужны. Если меняли учетные данные источника,
согласуйте их с PXF по справочнику стенда.
Примените свой файл из make gp-psql:
\set ON_ERROR_STOP on
\i /sql/stg/airports_ddl.sql
SELECT * FROM stg.airports_ext ORDER BY airport_code LIMIT 3;
В Postgres (make bookings-psql) выполните такой же запрос к
bookings.airports_data. Сверьте состав и порядок полей с DDL.
Если чтение не работает, начните с сообщения об ошибке и
диагностики STG.
Теперь напишите загрузку снимка. Продумайте, как ваш SQL отличит
повторное выполнение от нового запуска и сохранит историю.
Выполнять загрузку будет готовый DAG lab_pxf_airports.
Получите первый снимок и сравните его с источником готовой сверкой. Она проверяет ключи, все бизнес-поля и служебные метки. Зеленые задачи в Airflow показывают, что код выполнился; сверка помогает обнаружить ошибку в самих данных.
Первый запуск в Airflow и сверка с Postgres
Для сверки нужен uv с Python 3.11 из
окружения разработчика.
В терминале из корня репозитория сохраните исходный справочник:
mkdir -p data/lab9
uv run --no-project scripts/check_airports_snapshot.py export data/lab9/airports-before.json
Скрипт читает Postgres напрямую, минуя вашу внешнюю таблицу, и не перезаписывает существующий файл. Эта копия позволит сравнить первый снимок с источником даже после изменения названия аэропорта.
Откройте Airflow UI по адресу из .env (AIRFLOW_WEB_PORT), войдите с
AIRFLOW_USER и AIRFLOW_PASSWORD. Включите lab_pxf_airports, нажмите
Trigger DAG и дождитесь успеха всех задач. В Grid выберите запуск;
его Run ID подставьте в команду:
first_run='вставьте Run ID первого запуска'
uv run --no-project scripts/check_airports_snapshot.py check "$first_run" data/lab9/airports-before.json
Если задача упала, откройте ее Log. SQL-файлы доступны контейнеру
из рабочей папки: после правки пересобирать образ не нужно.
{{ run_id }} подставляет Airflow, поэтому файл загрузки не следует
выполнять напрямую через psql.
Испытайте загрузку
Повторное выполнение
Представьте, что после сбоя пришлось повторить уже выполненную задачу. Что произойдет с данными при повторном выполнении вашего SQL? За счет чего в одном снимке не появится вторая копия каждого аэропорта?
Повторите загрузку в том же запуске и снова выполните сверку первого снимка. При ошибке исправьте SQL и повторите опыт на том же Run ID.
Как повторить задачу, сохранив Run ID
В запуске первого снимка выберите load_airports_to_stg → Clear task.
Снимите Upstream, Downstream, Past, Future, Recursive
и Only Failed, если включены. В Affected Tasks должна остаться
только эта задача этого запуска. Нажмите Clear, дождитесь успеха,
затем так же повторите check_airports_dq.
Новый Trigger DAG создал бы другой Run ID. Здесь нужно повторное
выполнение с прежним _load_id, чтобы испытать защиту от дублей.
Если загрузка уже записала дубли или неверные значения, исправление SQL
само их не удалит.
Удалите из stg.airports строки только этого _load_id, затем повторите
исправленную загрузку и DQ в том же запуске. После успешной сверки повторите
их еще раз: теперь вы проверяете защиту от дублей на заполненном снимке.
Изменение в источнике
Теперь аэропорт переименовали. До новой загрузки предположите, где будет видно новое название: в Postgres, во внешней таблице, в первом снимке STG?
Измените русское название одного аэропорта, сохранив ключ и остальные языки. Для опыта ниже есть готовый SQL, который также сохраняет исходное название для восстановления.
Изменить название в Postgres
В make bookings-psql:
\set ON_ERROR_STOP on
CREATE TABLE public.lab9_airport_original AS
SELECT airport_code, airport_name
FROM bookings.airports_data ORDER BY airport_code LIMIT 1;
UPDATE bookings.airports_data AS a
SET airport_name = jsonb_set(
b.airport_name, '{ru}', to_jsonb((b.airport_name->>'ru') || ' [lab9]'), false
)
FROM public.lab9_airport_original AS b
WHERE a.airport_code = b.airport_code
RETURNING a.airport_code, b.airport_name AS original, a.airport_name AS changed;
Запрос изменяет один аэропорт. Если таблица копии уже существует после предыдущего опыта, сначала восстановите источник, сверьте результат и удалите таблицу копии. Затем можно начать новый опыт.
Найдите этот аэропорт в stg.airports_ext и stg.airports обычными
SELECT-запросами. Сопоставьте наблюдение со своим предположением.
Запустите lab_pxf_airports заново и рассмотрите оба снимка в STG.
Какое название хранится в каждом? Почему одного сравнения количества
строк недостаточно, чтобы заметить переименование?
Сверьте новый снимок с измененным источником, а первый — с исходным. Это обнаружит, например, загрузку старых данных под новым Run ID.
Сверить оба снимка
В том же терминале, где задан first_run:
uv run --no-project scripts/check_airports_snapshot.py export data/lab9/airports-after.json
next_run='вставьте Run ID нового запуска'
uv run --no-project scripts/check_airports_snapshot.py check "$next_run" data/lab9/airports-after.json
uv run --no-project scripts/check_airports_snapshot.py check "$first_run" data/lab9/airports-before.json
Если терминал закрывался, значения Run ID можно снова взять из Airflow.
Передайте снимок в ODS
Запустите bookings_to_gp_ods без параметров conf. Найдите измененный
аэропорт в ods.airports: название должно быть новым, а _load_id —
совпадать с последним запуском STG. Так вы увидите, что следующий слой
использовал результат вашей загрузки.
ODS выбирает общий батч четырех справочников: airports, airplanes,
routes, seats. Поэтому готовый lab_pxf_airports загружает все четыре,
используя те же SQL, что основной STG-DAG. Генератор новых дней и
транзакционные таблицы в этом опыте не участвуют.
Проверить выбор снимка и данные ODS
В Log задачи resolve_stg_batch_id строка Используем stg_batch_id=...
показывает выбранный Run ID. Он должен совпасть с next_run.
После завершения DAG выполните:
uv run --no-project scripts/check_airports_snapshot.py check "$next_run" data/lab9/airports-after.json --layer ods
Сверка учитывает преобразование JSON в русские названия и требует нужный
_load_id у всех строк ODS. Если выбран старый батч, посмотрите, завершились
ли все загрузки и DQ последнего запуска lab_pxf_airports.
Завершение работы
Верните исходное название и получите еще один общий снимок через
lab_pxf_airports. Проведите его по цепочке
bookings_to_gp_ods → bookings_to_gp_dds → bookings_to_gp_dm.
В ods.airports и dds.dim_airports должно вернуться исходное название.
Восстановить источник и сверить результат
В make bookings-psql:
UPDATE bookings.airports_data AS a
SET airport_name = b.airport_name
FROM public.lab9_airport_original AS b
WHERE a.airport_code = b.airport_code
RETURNING a.airport_code, a.airport_name;
После нового запуска lab_pxf_airports и ODS сравните восстановленный
снимок с исходной копией:
restored_run='вставьте Run ID запуска STG после восстановления'
uv run --no-project scripts/check_airports_snapshot.py check "$restored_run" data/lab9/airports-before.json
uv run --no-project scripts/check_airports_snapshot.py check "$restored_run" data/lab9/airports-before.json --layer ods
Повтор UPDATE восстановления безопасен. После успешной сверки выполните
в Postgres DROP TABLE public.lab9_airport_original;.
Если прервались на изменении источника,
продолжите с этого восстановления и нового запуска цепочки.
Для повторения всей лабораторной возьмите новые имена контрольных файлов.
При полной пересборке сохраните SQL-файлы: make clean удаляет тома.
Затем снова пройдите быстрый старт со своим решением.
Снимки в STG остаются историей опыта: первоначальный, с измененным названием и восстановленный. Последний общий снимок и текущий ODS снова содержат исходные значения; транзакционные данные остались от быстрого старта.
Результат работы — ваши два SQL-файла и объяснение их поведения: откуда берется каждый снимок, что защищает его от дублей при повторе и как изменение источника попадает в следующую загрузку.
Дальше — загрузки ods.airplanes и ods.seats.
Они используют уже подготовленный снимок, поэтому заново запускать STG
для начала следующей работы не нужно. Там вы будете преобразовывать поля
полученных данных и заменять текущее состояние в ODS.