Learning Platform
Глоссарий Troubleshooting
Урок 17.01 · 22 мин
Продвинутый
capstonearchitectureducklakepipeline-design

Проектирование пайплайна: от сырых файлов к DuckLake

Этот модуль — сквозной практический проект. На протяжении семи уроков мы построим один конкретный аналитический lakehouse целиком на DuckDB: спроектируем архитектуру, напишем ELT-слои, обработаем датасет больше оперативной памяти, сделаем партиционированные витрины с инкрементальными апдейтами, забенчмаркаем результат против Pandas и Spark, опубликуем витрину для браузера через DuckDB-WASM и в финале разберём архитектуру и проведём code review.

Каждый предыдущий модуль курса дал кусок этой картины: friendly SQL, чтение внешних данных, larger-than-memory исполнение, запись данных, DuckLake. Капстоун собирает их в одно работающее решение. Этот первый урок — про проектирование: какую задачу решаем, из каких слоёв состоит пайплайн и почему каждый слой именно такой.


Постановка задачи и датасет

Возьмём реалистичную задачу аналитической инженерии. Есть оператор городских такси-поездок. Сырые данные приходят дампами на объектное хранилище: исторические поездки — помесячными файлами Parquet (по файлу на месяц, формат стабильный), а справочник зон города — отдельным CSV (обновляется редко, формат «грязноватый»: смешанные регистры, лишние пробелы). Суммарный объём исторических поездок — несколько десятков гигабайт, заведомо больше RAM типичного ноутбука.

Аналитикам нужны витрины: выручка и число поездок по дням и зонам, средняя длительность и дистанция поездки, разбивка по способу оплаты. Витрины должны обновляться при появлении нового месячного файла — без полного пересчёта истории.

Сырые данные на объектном хранилище (s3:// или MinIO/локальная папка):

  raw/trips/year=2024/month=01/trips.parquet
  raw/trips/year=2024/month=02/trips.parquet
  ...
  raw/trips/year=2026/month=04/trips.parquet     -- ~28 месячных файлов
  raw/zones/zones.csv                            -- справочник зон, ~260 строк

Это типичная стартовая позиция: данные уже где-то лежат, форматы разные, объём не помещается в память, и нужен повторяемый пайплайн, а не разовый скрипт.


Почему DuckDB и DuckLake для этой задачи

Прежде чем рисовать слои, зафиксируем выбор инструментов — он определяет архитектуру.

DuckDB как движок. Он читает Parquet и CSV напрямую с объектного хранилища без отдельного шага загрузки, исполняет larger-than-memory агрегации со спиллом на диск, и весь пайплайн — это один процесс без сервера и кластера. Для «локального аналитического lakehouse» это точное попадание: не нужно поднимать Spark-кластер ради десятков гигабайт.

DuckLake как формат хранения витрин. Сырые файлы — это просто файлы, у них нет ни схемы-как-контракта, ни версий, ни ACID. Витрины же должны обновляться инкрементально и безопасно. DuckLake даёт лейкхаус-слой: данные в Parquet на хранилище, метаданные в SQL-каталоге, кросс-табличный ACID, снапшоты с time-travel, инкрементальные MERGE. Для слоя, который аналитики читают и который меняется новыми загрузками, это правильная основа.

NOTE

Граница ответственности: DuckDB — это движок (исполняет SQL, читает файлы, считает), DuckLake — это формат хранения (организует Parquet-файлы и метаданные в таблицы с ACID). Они не конкурируют: пайплайн читает движком DuckDB, а результат складывает в формат DuckLake. В капстоуне каталог DuckLake возьмём в SQLite — проект локальный и однопользовательский; для команды это был бы PostgreSQL.


Слои пайплайна: raw, staging, marts

Пайплайн строится по классической многослойной схеме. Каждый слой решает одну задачу и подаёт результат следующему.

Архитектура капстоун-пайплайна
RawСырые файлы как есть на объектном хранилище: помесячные Parquet с поездками и CSV-справочник зон. Их не меняют, только читают.
читаем как есть
StagingОчистка и приведение типов: один stg-объект на один источник. Чинит грязный CSV, кастует типы, переименовывает колонки в единый стиль. Бизнес-логики ещё нет.
чистим и типизируем
MartsБизнес-витрины: агрегаты по дням и зонам, метрики выручки и длительности. Это то, что читают аналитики. Хранится в DuckLake.
публикуем
ConsumersПотребители витрин: BI-инструменты, ноутбуки, а в уроке про публикацию — DuckDB-WASM в браузере.

Слой raw — сырые файлы, которые мы не трогаем. Принцип: исходные данные иммутабельны, пайплайн только читает их. Если что-то пошло не так, всегда можно перечитать raw заново. DuckDB обращается к raw напрямую — read_parquet и read_csv по путям с globs.

Слой staging — очистка «один к одному с источником». На каждый источник — один staging-объект: stg_trips для поездок, stg_zones для зон. Здесь и только здесь чинятся болячки источника: грязный CSV приводится в порядок, типы кастуются явно (строка-дата в DATE, текстовая сумма в DECIMAL), колонки переименовываются в единый snake_case. Бизнес-логики на этом слое нет — задача staging сделать данные чистыми и предсказуемыми, не более.

Слой marts — бизнес-витрины. Здесь происходит моделирование: соединение поездок со справочником зон, агрегация по дням и зонам, расчёт метрик. Это то, что увидят аналитики, и именно этот слой хранится в DuckLake — с ACID, снапшотами и инкрементальными апдейтами.

Зачем разделять staging и marts, а не делать всё одним запросом? Разделение даёт три вещи. Изоляция изменений источника: если поставщик переименовал колонку в Parquet, правка нужна только в stg_trips, marts не трогаются. Переиспользование: один stg_trips питает несколько витрин. Тестируемость: чистоту данных проверяем на staging, бизнес-корректность — на marts, и при сбое сразу видно, какой слой виноват.


Поток данных в проекте

Сведём архитектуру в конкретный поток, который реализуем в следующих уроках.

Сквозной поток данных капстоуна
raw/trips ParquetПомесячные Parquet-файлы поездок на объектном хранилище. Читаются globs-паттерном.
stg_tripsОчищенные типизированные поездки: касты типов, единый нейминг, отфильтрованный мусор.
JOIN зоны
mart_dailyВитрина выручки и поездок по дням и зонам. Партиционирована, хранится в DuckLake, обновляется через MERGE.
WASM / BIПубликация витрины: компактный Parquet для DuckDB-WASM в браузере и доступ для BI.

Распределение уроков модуля по этому потоку:

УрокЧто строимСлой
1 (этот)Архитектура и проектированиевесь пайплайн
2ELT: staging, очистка, моделированиеraw -> staging -> marts
3Out-of-core агрегация датасета больше RAMтяжёлый расчёт в marts
4Партиционированные витрины и MERGEmarts в DuckLake
5Бенчмаркинг против Pandas/Sparkпроверка marts-расчёта
6Публикация витрины через DuckDB-WASMподача
7Разбор архитектуры и code reviewвесь проект

Готовим окружение. Понадобится DuckDB 1.5.x, расширения httpfs (для объектного хранилища) и ducklake (для лейкхаус-слоя):

-- Расширения для капстоуна
INSTALL httpfs;   LOAD httpfs;
INSTALL ducklake; LOAD ducklake;

-- Лейкхаус для marts-слоя: каталог в SQLite, данные в папке
ATTACH 'ducklake:sqlite:capstone_catalog.sqlite' AS lake
  (DATA_PATH 'capstone_lake/');

-- Проверка
SELECT current_setting('memory_limit');

Если данные на S3 или совместимом хранилище (MinIO, R2), понадобится ещё secret с доступом — его настроим в следующем уроке вместе с чтением raw.


Принципы, которым следует проект

Зафиксируем правила, которые будут видны во всех последующих уроках.

  • Raw иммутабелен. Пайплайн только читает сырые файлы. Любое исправление — это код в staging, а не правка исходника.
  • Каждый слой — одна ответственность. Staging чистит, marts моделирует. Не смешиваем.
  • Идемпотентность. Повторный запуск пайплайна на тех же данных даёт тот же результат. Это требование к тому, как пишутся загрузки (увидим в уроке про MERGE).
  • Инкрементальность с самого начала. Витрины проектируются так, чтобы новый месячный файл добавлялся без пересчёта истории, — это закладывается в архитектуру партиционирования, а не прикручивается потом.
  • Контроль ресурсов явный. Раз датасет больше RAM, memory_limit и temp_directory задаются осознанно, а не оставляются по умолчанию.

Эти принципы — не бюрократия, а то, что отличает повторяемый production-пайплайн от разового скрипта. Дальше каждый урок будет реализовывать конкретный слой этой архитектуры.


Попробуй сам

Цель этого задания — подготовить и осмыслить проект, кода-расчётов здесь ещё нет.

Задания:

  1. Установите DuckDB 1.5.x. Выполните INSTALL httpfs; INSTALL ducklake; и подключите локальный DuckLake-лейкхаус командой ATTACH из урока. Убедитесь, что каталог-файл и папка данных создались.
  2. Нарисуйте на бумаге слои пайплайна (raw, staging, marts, consumers) и для каждого подпишите: какую одну задачу он решает и что будет, если его убрать.
  3. Сформулируйте письменно, почему справочник зон (грязный CSV) и поездки (стабильный Parquet) проходят через отдельные staging-объекты, а не через один.
  4. Объясните себе, почему именно слой marts хранится в DuckLake, а слой raw — нет. Какие свойства DuckLake (ACID, снапшоты, MERGE) нужны marts и не нужны сырым файлам.
dbt: sources, staging, marts — трёхслойная архитектура
Проверка знанийKnowledge check
Из каких слоёв состоит капстоун-пайплайн, какую ответственность несёт каждый и почему именно слой marts хранится в DuckLake?
ОтветAnswer
Пайплайн состоит из слоёв raw, staging и marts, питающих потребителей. Raw — это сырые файлы на объектном хранилище (помесячные Parquet с поездками и грязный CSV-справочник зон); они иммутабельны, пайплайн только читает их, и при сбое всегда можно перечитать заново. Staging — очистка один к одному с источником: на каждый источник свой staging-объект, здесь и только здесь чинятся болячки источника (грязный CSV приводится в порядок, типы кастуются явно, колонки переименовываются в единый стиль), бизнес-логики ещё нет. Marts — бизнес-витрины: соединение поездок со справочником зон, агрегация по дням и зонам, расчёт метрик; это то, что читают аналитики. Разделение staging и marts даёт изоляцию изменений источника (правка только в staging), переиспользование одного staging несколькими витринами и тестируемость (чистота проверяется на staging, бизнес-корректность на marts). Слой marts хранится в DuckLake потому, что именно ему нужны свойства лейкхауса: ACID и снапшоты для безопасных обновлений, time-travel для воспроизводимости, инкрементальный MERGE для добавления нового месячного файла без пересчёта истории. Сырым файлам слоя raw эти свойства не нужны — это просто иммутабельные исходники. DuckDB при этом выступает движком, который читает файлы и считает, а DuckLake — форматом хранения витрин; они дополняют друг друга, а не конкурируют.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Из каких слоёв состоит капстоун-пайплайн и какую ответственность несёт staging-слой?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 7