# Прием airports через PXF: материалы автора Лабораторная [#9](https://git.dementev.space/ddmitry/airflow-greenplum/issues/9) из [серии #8](https://git.dementev.space/ddmitry/airflow-greenplum/issues/8). Студент работает по [инструкции в main](https://git.dementev.space/ddmitry/airflow-greenplum/src/branch/main/docs/assignment/pxf_airports.md). Общие принципы программы находятся в [авторской заметке](labs_development.md). ## Место и самостоятельная часть Работа идет после быстрого старта и знакомства с моделью, перед существующими `ods.airplanes` и `ods.seats`. Входом служит прошедшая эталонная цепочка до `dm.sales_report` на учебной `main`; пустые студенческие таблицы не мешают начать работу. Полный `bookings_validate` не является условием входа. Выбран `airports`: он небольшой, содержит ключ, многоязычные JSON и координаты, а его готовая загрузка ODS дает наблюдаемый результат преобразования. Студент удаляет внешний DDL из `sql/stg/airports_ddl.sql` и заменяет `sql/stg/airports_load.sql` заглушкой. В базе удаляет внешний объект и все снимки только `stg.airports`. Без очистки прошлые строки могли бы скрыть отсутствие собственной загрузки. Внутренний DDL, JDBC-конфигурация и DQ остаются готовыми. Добавлен готовый `lab_pxf_airports`: восемь PostgresOperator выполняют существующие загрузки и проверки четырех справочников. Студент задает состав и порядок полей внешней таблицы, `LOCATION`, затем пишет получение снимка с ключом и метками. Близкий пример — `airplanes`. Физическая организация внутренней таблицы и самостоятельная оркестрация относятся к следующим работам. ## Устройство урока Основной текст строится вокруг собственной загрузки и опытов с данными. Сначала студент пишет SQL по требованиям и близкому примеру, затем предполагает результат повторного выполнения и переименования аэропорта, наблюдает данные и объясняет различия. Передача нового названия в ODS показывает применение его работы в следующем слое. Команды подготовки, первые действия Airflow, сверка и восстановление находятся в раскрываемых блоках рядом с соответствующим действием. Проверки остаются готовыми: написание собственной DQ относится к дальнейшим заданиям. Результат студента — два SQL-файла и объяснение опытов; собирать отчет из JSON, Run ID и логов не требуется. Обозначения A/B/C, проверки намеренно неверной реализации и полный протокол приемки относятся к авторским материалам. Они подтверждают пригодность лабораторной, но не задают структуру урока. Одного сокращения формулировок было бы недостаточно: оно сохранило бы последовательность сбора доказательств вместо работы с собственной загрузкой. Демонстрационный разбор также не дал бы предусмотренной программой самостоятельной практики. ## Полное решение Эталон уже содержится в этой ветке: - [airports_ddl.sql](../../sql/stg/airports_ddl.sql): шесть TEXT-полей, `pxf://bookings.airports_data?PROFILE=JDBC&SERVER=bookings-db`, `FORMAT 'CUSTOM' (formatter='pxfwritable_import')`. - [airports_load.sql](../../sql/stg/airports_load.sql): чтение внешней таблицы, `_load_id = '{{ run_id }}'`, две метки `now()`, защита `NOT EXISTS` по паре `(_load_id, airport_code)`. - [airports_dq.sql](../../sql/stg/airports_dq.sql): базовая обратная связь DAG. - [airports_load.sql для ODS](../../sql/ods/airports_load.sql): выбор батча, извлечение `ru` и замена текущего снимка. Для воспроизведения автор может после вычитания вернуть два исходных файла из сохраненной копии. В учебной ветке они также остаются готовыми при первом запуске: вычитание выполняется самим студентом во время работы. Скрывать ответ технически не требуется; самостоятельность проверяется опытами и объяснением результата. ## Почему нужны эти проверки Готовая [сверка в main](https://git.dementev.space/ddmitry/airflow-greenplum/src/branch/main/scripts/check_airports_snapshot.py) экспортирует источник напрямую из Postgres, без внешней таблицы студента. Поэтому неверный `LOCATION` не становится одновременно ошибкой загрузки и ее контрольного источника. В JSON сохраняются все бизнес-поля, а не только выбранное русское имя. Перезапись контрольного файла запрещена. В STG проверяются ключи, отсутствие дублей внутри батча, все бизнес-поля, `_load_id`, наличие `_load_ts` и `event_ts`. JSON сравнивается по содержимому, чтобы порядок свойств не влиял на результат. В ODS проверяется вся таблица, русские значения названий и точный STG `_load_id` у каждой строки. Штатная DQ сверяет количество и обязательные поля, поэтому сама по себе не отвергнет старое непустое название с правильным числом строк. | Случай | Наблюдаемый результат | |---|---| | Вычитание | STG пуст; внешняя таблица отсутствует; независимая сверка отказывает | | A | Все ключи и бизнес-поля совпадают с прямым экспортом источника | | Повтор A | Clear только загрузки аэропортов, затем ее DQ в том же запуске; строки сохраняются, генератор не повторяется | | Изменение источника | Сохранен исходный JSON одного аэропорта; изменен только `ru` | | Неверная старая копия | A или его копия с новым `_load_id` не совпадает с контрольным источником B при равном числе строк | | B | B содержит новое имя; A все еще совпадает с исходным экспортом | | ODS | Все четыре справочника имеют B; resolver без `conf` выбирает B; ODS содержит B и новое имя | | Восстановление C | Источник в точности равен исходному A; новый общий C проходит ODS → DDS → DM | Для повторов A используется Clear отдельных задач. A/B/C создаются через `lab_pxf_airports`: повтор снимка не требует нового транзакционного дня. Это стало отдельной границей при подготовке опыта: полные запуски STG привязывали каждый контроль справочника к длительной генерации Bookings. Учебный DAG явно исключает генератор и транзакционные загрузки, но использует те же SQL-файлы снимков. Основной `bookings_to_gp_stage` сохраняет свое поведение. Автоматический resolver выбирает последний общий ID по времени готовности. Наличие ID во всех таблицах не доказывает их полноту — нужны DQ и сверка. Передача `stg_batch_id` через `conf` обошла бы автоматический выбор, поэтому в проверочном опыте ODS запускается с пустым `conf`. ## Выход и переход В `stg.airports` остаются A/B/C; старые снимки аэропортов удалены в начале. В остальных справочниках остаются также снимки быстрого старта. Транзакционные таблицы сохраняют данные подготовки. B сохраняет учебное изменение как историю; последний общий C и текущий ODS содержат восстановленные значения. Источник восстанавливается из постоянной таблицы `public.lab9_airport_original`, поэтому закрытие psql не теряет копию. Повтор UPDATE восстановления безопасен; таблица удаляется только после сверки. Следующая работа берет общий C для `ods.airplanes` и `ods.seats`, без нового STG. Затем сохраняется прежний маршрут измерений и витрин. Работы #10–#14 остаются отдельными задачами серии; эта лабораторная не добавляет их заглушки и не меняет текущие требования к ним. ## Проверочный прогон Команды, версии и наблюдения сохраняются в [протоколе прогона](../reports/2026-09-22-pxf-airports.md). Проверять нужно учебную `main`: полный `solution` заполняет дополнительные таблицы и не подтверждает проходимость первой работы с учебными заглушками.