dbt Core превращает SQL-преобразования в проект с явными зависимостями, повторяемыми запусками, тестами и каталогом данных. Для первого запуска достаточно Python, пакета dbt-duckdb и локального файла DuckDB: облачное хранилище, оркестратор и отдельный сервер не требуются.
Ниже собран минимальный рабочий проект: CSV с заказами загружается в DuckDB, модель очищает записи, вторая модель считает дневную выручку, а dbt проверяет ключи, пустые значения и допустимые статусы. В конце появится локальная документация dbt docs с графом зависимостей.
Что даёт dbt в SQL-проекте
Обычный набор SQL-файлов быстро становится трудно поддерживать: непонятно, какой запрос нужно запускать первым, какие таблицы служат входом и где сломалось качество данных. dbt вводит для этого несколько простых сущностей.
- Модель - SQL-файл в каталоге
models. dbt компилирует запрос и создаёт представление или таблицу. - Источник - уже существующая таблица с исходными данными. Он описывается в YAML и вызывается через
source(). - Ссылка на модель - вызов
ref(). Он строит зависимость между моделями и избавляет от жёстко прописанных имён таблиц. - Тест - SQL-проверка, которая возвращает строки-нарушения. Встроенные тесты покрывают типовые инварианты: уникальность, заполненность, набор допустимых значений и ссылочную целостность.
- Документация - описание моделей, колонок и источников, связанное с графом проекта.
dbt не забирает исходные данные из API и не заменяет планировщик задач. Его зона ответственности - преобразования внутри аналитического хранилища или базы, контроль качества и описание слоя данных. Для локального обучения DuckDB удобен тем, что база хранится в одном файле и запускается без сервера.
Установка dbt Core и создание проекта
Создайте отдельное виртуальное окружение. Это исключит конфликт зависимостей dbt с другими Python-проектами.
mkdir analytics_dbt
cd analytics_dbt
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install dbt-duckdb
В PowerShell активация окружения выглядит иначе:
.\.venv\Scripts\Activate.ps1
Пакет dbt-duckdb устанавливает адаптер DuckDB и совместимую версию dbt Core. Проверьте, что CLI видит установленный адаптер:
dbt --version
Затем инициализируйте проект:
dbt init analytics_dbt
cd analytics_dbt
Команда создаст базовые файлы проекта и каталог профиля в домашней директории пользователя. Для учебного примера достаточно следующих частей структуры:
analytics_dbt/
├── dbt_project.yml
├── models/
│ ├── sources.yml
│ ├── staging/
│ └── marts/
├── seeds/
└── data/
Структура dbt проектов обычно разделяет модели по слоям. В staging приводят сырые данные к предсказуемому виду, в marts собирают таблицы для аналитики, отчётов или подготовки датасетов.
Настройка профиля DuckDB
dbt хранит параметры подключения отдельно от SQL-кода. Откройте файл ~/.dbt/profiles.yml и добавьте профиль с именем проекта:
analytics_dbt:
target: dev
outputs:
dev:
type: duckdb
path: data/analytics.duckdb
schema: main
threads: 4
Поле path задаёт файл базы. Перед первым запуском создайте каталог data, иначе DuckDB не сможет создать файл по вложенному пути:
mkdir -p data
dbt debug
dbt debug проверяет конфигурацию проекта, профиль и подключение. Успешный результат на этом шаге экономит время: ошибка в имени профиля или пути к базе проявится до компиляции моделей.
Минимальный dbt_project.yml для примера выглядит так:
name: 'analytics_dbt'
version: '1.0.0'
config-version: 2
profile: 'analytics_dbt'
model-paths: ['models']
seed-paths: ['seeds']
models:
analytics_dbt:
+materialized: view
Параметр +materialized: view делает представление форматом по умолчанию для моделей. Для тяжёлых витрин обычно выбирают таблицу, а для разработки представления удобны тем, что не дублируют данные в базе.
Исходные данные и декларация source
Seeds позволяют загрузить небольшой CSV в целевую базу без отдельного загрузочного скрипта. Создайте файл seeds/orders.csv:
order_id,user_id,created_at,amount,status
1,101,2026-09-01 10:15:00,1490.00,paid
2,102,2026-09-01 11:30:00,890.00,pending
3,101,2026-09-02 09:05:00,1490.00,paid
4,103,2026-09-02 12:40:00,490.00,cancelled
Загрузите CSV командой:
dbt seed
При настройке выше dbt создаст в схеме main таблицу orders. Теперь опишите её как источник в models/sources.yml:
version: 2
sources:
- name: raw
description: Исходные заказы, загруженные из CSV.
schema: main
tables:
- name: orders
description: Одна строка соответствует одному заказу.
В модели источник вызывается конструкцией {{ source('raw', 'orders') }}. dbt получает физическое имя объекта из профиля и YAML-конфигурации, поэтому SQL не привязан к конкретному имени базы или схеме. При переезде с DuckDB в warehouse меняют адаптер и профиль, а не десятки SQL-файлов.
DuckDB годится и для более реалистичных экспериментов с Parquet. Практику работы с удалёнными файлами через SQL разбирает руководство по анализу датасетов Hugging Face Hub через DuckDB.
Создание моделей и зависимостей
Первая модель приводит поля к рабочему формату. Создайте models/staging/stg_orders.sql:
{{ config(materialized='view') }}
with source_orders as (
select *
from {{ source('raw', 'orders') }}
)
select
cast(order_id as bigint) as order_id,
cast(user_id as bigint) as user_id,
try_cast(created_at as timestamp) as created_at,
try_cast(amount as decimal(12, 2)) as amount,
lower(trim(status)) as status
from source_orders
where order_id is not null
Здесь try_cast возвращает NULL для значения, которое нельзя преобразовать. Такой подход не скрывает проблему: следующая проверка поймает пустой created_at или amount, а запуск не оборвётся на первой некорректной строке.
Вторая модель использует ref() вместо обращения к физическому имени stg_orders. Создайте models/marts/fct_daily_revenue.sql:
{{ config(materialized='table') }}
select
cast(created_at as date) as order_date,
count(*) as paid_orders,
sum(amount) as revenue
from {{ ref('stg_orders') }}
where status = 'paid'
group by 1
Вызов ref('stg_orders') фиксирует зависимость: dbt сначала построит stg_orders, затем витрину дневной выручки. Команда dbt compile покажет SQL после подстановки Jinja-конструкций, а dbt run создаст модели в DuckDB.
dbt compile
dbt run
Материализация table полезна для агрегата, который читают много раз. Она занимает место в файле базы, зато не пересчитывает агрегацию при каждом запросе. Выбор между view и table зависит от объёма данных, частоты обновления и стоимости вычислений.
Встроенные тесты dbt
Тесты описываются рядом с моделями в YAML. Создайте файл models/staging/schema.yml:
version: 2
models:
- name: stg_orders
description: Очищенные заказы для дальнейших расчётов.
columns:
- name: order_id
description: Идентификатор заказа.
tests:
- unique
- not_null
- name: user_id
description: Идентификатор клиента.
tests:
- not_null
- name: created_at
description: Время создания заказа.
tests:
- not_null
- name: amount
description: Сумма заказа.
tests:
- not_null
- name: status
description: Статус заказа.
tests:
- accepted_values:
values: ['paid', 'pending', 'cancelled']
unique найдёт повторяющиеся идентификаторы, not_null вернёт записи с пропущенным значением, а accepted_values остановит появление неожиданного статуса вроде refund_pending. Тесты не исправляют данные. Они превращают нарушение контракта в видимую ошибку пайплайна.
Запустите проверки отдельно:
dbt test
Для первого полного прогона удобна команда dbt build. Она создаёт seed, строит модели в порядке зависимостей и запускает относящиеся к ним тесты.
dbt build
При сбое dbt выводит имя теста и модель. Дальше нужно посмотреть строки-нарушения в DuckDB, проверить исходный CSV или логику преобразования. Отключать тест ради зелёного CI не стоит: так проблема просто переезжает в отчёт или обучающий датасет.
Проверка ссылочной целостности
Когда появится таблица клиентов stg_customers, для поля user_id можно добавить тест связи:
- name: user_id
tests:
- not_null
- relationships:
to: ref('stg_customers')
field: user_id
Проверка вернёт заказы, для которых нет клиента. Это особенно полезно перед расчётом метрик по пользователям или передачей таблицы в feature pipeline. Тест предполагает, что модель stg_customers уже существует и содержит колонку user_id.
Документация dbt docs
Документация dbt docs строится из YAML-описаний и метаданных базы. После dbt build выполните две команды:
dbt docs generate
dbt docs serve
dbt docs generate создаёт артефакты проекта, включая каталог объектов и граф зависимостей. dbt docs serve поднимает локальный веб-интерфейс. В нём можно открыть модель, увидеть описание колонок, используемый SQL, тесты и связи с источниками.
Полезная документация требует описывать не только технические поля. Фраза «сумма заказа» слабее, чем «сумма оплаченного заказа в рублях до вычета комиссии», если именно такое правило применяет бизнес-логика. Точное описание снижает риск неверной интерпретации витрины через несколько месяцев.
Рабочий цикл и типовые ошибки
Для небольшой локальной базы достаточно короткого цикла: меняете SQL или YAML, запускаете dbt build, затем обновляете документацию командой dbt docs generate. Перед изменением структуры полезно выполнить dbt compile и убедиться, что Jinja-шаблоны развернулись в ожидаемый SQL.
| Симптом | Вероятная причина | Что проверить |
|---|---|---|
dbt debug не находит профиль |
Имя профиля не совпадает с profile в dbt_project.yml |
Секцию analytics_dbt в profiles.yml |
Источник raw.orders не найден |
Seed ещё не загружен или указана другая схема | Запуск dbt seed, параметр schema: main |
Модель строится, тест not_null падает |
try_cast встретил некорректное значение или источник содержит пропуск |
Строки с пустым полем и правила очистки |
| Витрина считает меньше строк, чем источник | Фильтр в модели исключает статусы или записи без ключа | Условия where и ожидаемое бизнес-правило |
DuckDB подходит для прототипов, локальной аналитики и воспроизводимых примеров. При совместной работе команды нужно отдельно решить, где будет лежать общая база, как запускать dbt по расписанию, как хранить секреты и кто владеет контрактами на исходные таблицы.
Где dbt полезен в AI-пайплайнах
AI-системы часто зависят от тех же проблем качества данных, что и аналитика. Перед разметкой, fine-tuning, RAG-индексацией или расчётом метрик можно очистить записи, привести даты и идентификаторы к единому типу, отсеять дубликаты и проверить обязательные поля. Модель dbt фиксирует эти правила как код, а тесты сигнализируют об их нарушении.
Например, таблица с промптами для оценки LLM может проходить тесты на уникальный идентификатор, непустой текст запроса, допустимый язык и связь с набором задач. Для команд, которые собирают и развивают открытые датасеты, полезен разбор инициативы Data Is Better Together от Hugging Face и Argilla.
dbt не заменит валидатор разметки, контроль токсичности или оценку качества ответов модели. Он хорошо закрывает слой табличных преобразований, где правила можно выразить SQL-запросом и проверкой результата.
Минимальный чек-лист проекта
- Установить
dbt-duckdbв виртуальное окружение. - Настроить профиль DuckDB и проверить его через
dbt debug. - Загрузить учебный CSV командой
dbt seed. - Описать исходные таблицы через
source(). - Собрать слой очистки и витрину через
ref(). - Добавить проверки
unique,not_nullиaccepted_values. - Запускать
dbt buildперед публикацией новых данных. - Сгенерировать документацию через
dbt docs generate.
После этого минимального проекта следующий практический шаг - заменить учебный CSV реальным источником, добавить тесты под правила предметной области и запускать dbt в CI или планировщике. SQL останется центром трансформаций, а зависимости, проверки и документация перестанут жить в памяти автора запросов.