DuckDB в пайплайнах: dbt-duckdb, Ibis, ноутбуки
Предыдущие уроки показали DuckDB как библиотеку, которую вызывают напрямую: duckdb.sql(...), Relational API. Но в реальных проектах DuckDB чаще встречается как движок внутри инструмента — фреймворка трансформаций, библиотеки построения запросов, ноутбука. Этот урок — обзорный: где DuckDB живёт в Python data-стеке, какую роль играет в трёх ключевых инструментах и почему именно его так часто выбирают локальным движком.
Почему DuckDB удобен как встроенный движок
dbt: настройка profiles.yml для DuckDB dbt: первая SQL-модель в DuckDBПрежде чем разбирать конкретные инструменты, поймём, что делает DuckDB хорошим выбором для встраивания. Причины — те самые свойства из всего курса, собранные вместе:
- Embedded, без сервера. DuckDB — библиотека
pip install duckdb. Инструменту не нужно поднимать и поддерживать отдельную СУБД, оркестрировать процессы, настраивать сеть. Встроил библиотеку — и есть полноценный SQL OLAP-движок. - Полноценный SQL и оптимизатор. Это не «обёртка над файлами», а движок с настоящим оптимизатором, larger-than-memory исполнением, ACID. Инструмент может опереться на серьёзную аналитику.
- Zero-copy с Python data-стеком. DuckDB бесшовно обменивается данными с Pandas, Polars, Arrow (уроки 1-2). Встроенный движок не создаёт барьера на границе с остальным Python-кодом.
- Скорость на одной машине. Векторизация, колоночное хранение, морсель-параллелизм дают производительность, которой для локальной разработки и средних данных хватает с запасом.
Итог: DuckDB даёт инструменту мощь warehouse-движка без эксплуатационной стоимости warehouse. Это и есть причина его повсеместности в современных Python-инструментах данных.
dbt-duckdb: DuckDB как движок трансформаций
dbt — стандартный фреймворк для слоя трансформаций (буква T в ELT): SQL-модели, зависимости между ними через ref(), тесты, документация, материализации. Сам dbt не исполняет SQL — он его компилирует и отправляет в warehouse через адаптер. Для каждого warehouse свой адаптер: dbt-snowflake, dbt-bigquery, dbt-postgres.
dbt-duckdb — адаптер, который делает движком исполнения моделей DuckDB. С ним dbt-проект работает поверх DuckDB: модели материализуются как таблицы и view в .duckdb-файле, источниками могут быть Parquet/CSV-файлы и таблицы внешних баз, всё считает локальный векторизованный движок.
Что это даёт:
- Локальная разработка без облака. dbt-проект разрабатывается и тестируется целиком локально, без аккаунта в Snowflake/BigQuery и без расходов на облачный compute. Логику моделей пишут и проверяют на ноутбуке.
- Полноценный аналитический пайплайн на одной машине. Для проектов умеренного масштаба DuckDB через dbt-duckdb — не «черновик для будущего warehouse», а самодостаточное production-решение.
- CI/CD дёшево. Прогон dbt-тестов в CI на DuckDB не требует поднимать warehouse — pipeline быстрый и бесплатный.
# profiles.yml — конфигурация dbt с адаптером duckdb
my_project:
target: dev
outputs:
dev:
type: duckdb
path: 'analytics.duckdb' # модели материализуются в этот файл
-- Модель dbt: обычный SQL, движок — DuckDB
-- Источник — Parquet-файл прямо из модели
SELECT region, SUM(amount) AS total_revenue
FROM read_parquet('s3://bucket/sales/*.parquet')
GROUP BY region
Ibis: один Python-API, разные движки
Ibis — Python-библиотека для построения аналитических запросов методами, похоже на Relational API из прошлого урока: .filter(), .aggregate(), .join(). Но у Ibis есть своя большая идея — переносимость между движками.
Один и тот же код Ibis может исполняться на разных бэкендах: DuckDB, PostgreSQL, BigQuery, Snowflake, Spark и других. Ibis строит абстрактное выражение запроса, а на этапе исполнения компилирует его в SQL конкретного бэкенда. Вы пишете запрос один раз — а где он выполнится, решает выбор бэкенда.
DuckDB — бэкенд Ibis по умолчанию и рекомендуемый для локальной работы. Типичный паттерн: разрабатываете и отлаживаете запрос на DuckDB локально (быстро, бесплатно, без облака), а в продакшене тот же код Ibis переключаете на «большой» бэкенд, если данные переросли одну машину.
import ibis
# Бэкенд — DuckDB, по умолчанию для локальной работы
con = ibis.duckdb.connect()
t = con.read_parquet("sales.parquet")
# Запрос строится методами Ibis — переносим между движками
expr = (
t.filter(t.amount > 100)
.group_by("region")
.aggregate(total=t.amount.sum())
)
# Ibis компилирует выражение в SQL DuckDB и исполняет
print(expr.execute()) # результат — Pandas DataFrame
Ibis и Relational API DuckDB решают похожую задачу — построение запроса методами Python — но с разным акцентом. Relational API привязан к DuckDB и работает напрямую с его движком. Ibis — это слой переносимости поверх многих движков, и DuckDB для него один из бэкендов. Если работаете только с DuckDB, Relational API проще и прямее; если нужен один код для нескольких движков — Ibis.
DuckDB в ноутбуках
Jupyter-ноутбук — основная среда исследовательского анализа в Python, и DuckDB вписан в неё особенно органично. Почему:
- Нулевая настройка.
pip install duckdb,import duckdb— и в ячейке доступен SQL. Не нужно поднимать сервер, заполнять connection string, держать процесс БД. - Естественное соседство с DataFrame. В ноутбуке постоянно живут Pandas/Polars-переменные. Через replacement scan они мгновенно доступны SQL-запросу, а результат через
.df()так же мгновенно возвращается в ячейку как DataFrame. SQL и Python чередуются ячейка за ячейкой без трения. - Красивый вывод. Результат запроса DuckDB печатается в ноутбуке аккуратной таблицей; для графиков результат забирается в DataFrame и идёт в matplotlib/plotly.
- Тяжёлые данные локально. Ноутбук обычно ограничен памятью Pandas. DuckDB снимает это ограничение: larger-than-memory исполнение (отдельный модуль курса) позволяет в той же ячейке считать агрегаты по датасету больше RAM, чего чистый Pandas не может.
# Типичная ячейка ноутбука: SQL над DataFrame, результат — снова DataFrame
import duckdb
import pandas as pd
events = pd.read_json("events.json") # данные уже в ноутбуке
summary = duckdb.sql("""
SELECT event_type, COUNT(*) AS n, AVG(duration) AS avg_dur
FROM events
GROUP BY event_type
ORDER BY n DESC
""").df() # обратно в DataFrame для графика
Многие предпочитают DuckDB в ноутбуке как замену тяжёлым Pandas-конструкциям: сложную группировку с оконными функциями нагляднее и быстрее выразить SQL-запросом, чем цепочкой Pandas-вызовов, — а данные при этом не покидают ноутбук.
DuckDB в ноутбуке и dbt-duckdb для пайплайна не делают DuckDB заменой распределённого warehouse во всех сценариях. DuckDB — движок одной машины: его потолок — ресурсы этой машины. Для данных, которые не помещаются на один узел даже со спиллом на диск, и для нагрузок с многими одновременными писателями нужен распределённый движок. Сила DuckDB — локальная разработка, средние данные и роль быстрого встроенного движка. Выбирайте по масштабу.
Попробуй сам
Для задания: pip install duckdb ibis-framework[duckdb] и Jupyter (или любой ноутбук-движок).
- В ноутбуке выполните несколько ячеек, чередуя Python и SQL: создайте DataFrame в одной ячейке, запросите его через
duckdb.sql()в следующей, постройте график по результату в третьей. Прочувствуйте, как SQL и Python соседствуют без трения. - Установите Ibis с бэкендом DuckDB. Постройте запрос методами Ibis (
.filter().group_by().aggregate()) и исполните через.execute(). Сравните стиль с Relational API DuckDB из прошлого урока. - Изучите по документации dbt-duckdb минимальный
profiles.ymlсtype: duckdb. Сформулируйте, что меняется в dbt-проекте при смене адаптера с dbt-snowflake на dbt-duckdb и что остаётся прежним. - Сформулируйте словами три ситуации, где DuckDB как встроенный движок — отличный выбор, и одну, где нужен распределённый warehouse. Опирайтесь на масштаб данных и модель конкурентности.
dbt: адаптеры и как движок подключается к dbt