Перейти к содержанию
Публикация AiManual

Практическое руководство по dbt: установка, модели, тестирование и документация для работы с данными

Пошагово соберите локальный dbt-проект на DuckDB: установите dbt Core, загрузите данные, создайте SQL-модели, добавьте проверки качества и откройте документацию

Коротко

Что будет в материале

  1. 01

    Что даёт dbt в SQL-проекте

  2. 02

    Установка dbt Core и создание проекта

  3. 03

    Настройка профиля DuckDB

  4. 04

    Исходные данные и декларация source

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-запросом и проверкой результата.

Минимальный чек-лист проекта

  1. Установить dbt-duckdb в виртуальное окружение.
  2. Настроить профиль DuckDB и проверить его через dbt debug.
  3. Загрузить учебный CSV командой dbt seed.
  4. Описать исходные таблицы через source().
  5. Собрать слой очистки и витрину через ref().
  6. Добавить проверки unique, not_null и accepted_values.
  7. Запускать dbt build перед публикацией новых данных.
  8. Сгенерировать документацию через dbt docs generate.

После этого минимального проекта следующий практический шаг - заменить учебный CSV реальным источником, добавить тесты под правила предметной области и запускать dbt в CI или планировщике. SQL останется центром трансформаций, а зависимости, проверки и документация перестанут жить в памяти автора запросов.

Подписаться на канал