Перейти к основному содержимому

Контракты моделей

Связанная документация

Зачем определять контракт?

Определение модели dbt так же просто, как написание SQL-запроса select. Ваш запрос естественным образом создает набор данных с именами и типами столбцов на основе выбранных вами столбцов и применяемых трансформаций.

Хотя это идеально подходит для быстрого и итеративного развития, для некоторых моделей постоянное изменение структуры возвращаемого набора данных представляет риск, когда другие люди и процессы запрашивают эту модель. Лучше определить набор предварительных "гарантий", которые определяют структуру вашей модели. Мы называем этот набор гарантий "контрактом". При построении вашей модели dbt проверит, что трансформация вашей модели создаст набор данных, соответствующий ее контракту, или не сможет построить модель.

Где поддерживаются контракты?

В настоящее время контракты моделей поддерживаются для:

  • SQL моделей.
  • Моделей, материализованных как одна из следующих:
    • table
    • view — Представления предлагают ограниченную поддержку имен столбцов и типов данных, но не constraints.
    • incremental — с on_schema_change: append_new_columns или on_schema_change: fail.
  • Определенных платформ данных, но поддерживаемые и применяемые constraints варьируются в зависимости от платформы.

Контракты моделей не поддерживаются для:

  • Python моделей.
  • materialized view или ephemeral-материализованных SQL моделей.
  • Пользовательских материализаций (если не добавлено автором).
  • Моделей с рекурсивными в BigQuery.
  • Других типов ресурсов, таких как sources, seeds, snapshots и так далее.

Как определить контракт

Предположим, у вас есть модель с запросом, как:

models/marts/dim_customers.sql
-- много SQL

final as (

select
customer_id,
customer_name,
-- ... и многое другое ...
from ...

)

select * from final

Чтобы применить контракт модели, установите enforced: true в конфигурации contract.

Когда контракт применяется, он должен включать name и data_type каждого столбца (где data_type соответствует одному из тех, которые понимает ваша платформа данных).

Если ваша модель материализована как table или incremental, и в зависимости от вашей платформы данных, вы можете дополнительно указать constraints, такие как not_null (содержащий нулевые значения).

models/marts/customers.yml
models:
- name: dim_customers
config:
contract:
enforced: true
columns:
- name: customer_id
data_type: int
constraints:
- type: not_null
- name: customer_name
data_type: string
...

При построении модели с определенным контрактом dbt будет делать две вещи по-другому:

  1. dbt выполнит проверку "предварительного полета", чтобы убедиться, что запрос модели вернет набор столбцов с именами и типами данных, соответствующими тем, которые вы определили. Эта проверка не зависит от порядка столбцов, указанных в вашей модели (SQL) или спецификации YAML.
  2. dbt включит имена столбцов, типы данных и ограничения в DDL-запросы, которые он отправляет на платформу данных, которые будут применяться при построении или обновлении таблицы модели, и упорядочит столбцы в соответствии с контрактом, а не вашей моделью dbt.

Поддержка ограничений платформы

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

  • Определяемые и применяемые — Модель не будет построена, если она нарушает ограничение.
  • Определяемые и не применяемые — Платформа поддерживает указание типа ограничения, но модель все равно может быть построена, даже если построение модели нарушает ограничение. Это ограничение существует только для целей метаданных. Этот подход более типичен для облачных хранилищ данных, чем для транзакционных баз данных, где более распространено строгое соблюдение правил.
  • Не определяемые и не применяемые — Вы не можете указать тип ограничения для платформы.
Тип ограниченияОпределяемоеПрименяемое
not_null
primary_key
foreign_key
unique
check

Часто задаваемые вопросы

Для каких моделей следует определять контракты?

Любая модель, соответствующая описанным выше критериям, может определить контракт. Мы рекомендуем определять контракты для "публичных" моделей, на которые полагаются в дальнейшем.

  • Внутри dbt: Общие с другими группами, другими командами и другими проектами dbt.
  • Вне dbt: Отчеты, панели управления или другие системы и процессы, которые ожидают, что эта модель будет иметь предсказуемую структуру. Вы можете отразить эти дальнейшие использования с помощью exposures.

Чем контракты отличаются от тестов?

Контракт модели определяет структуру возвращаемого набора данных. Если логика модели или входные данные не соответствуют этой структуре, модель не строится.

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

В некоторых случаях вы можете заменить тест данных его эквивалентным ограничением. Это имеет преимущество гарантии проверки во время построения и, вероятно, требует меньше вычислительных ресурсов (стоимости) на вашей платформе данных. Предпосылки для замены теста данных ограничением:

  • Убедитесь, что ваша платформа данных может поддерживать и применять необходимое вам ограничение. Большинство платформ применяют только not_null.
  • Материализация вашей модели как table или incremental (не view или ephemeral).
  • Определение полного контракта для этой модели, указав name и data_type каждого столбца.

Почему тесты не являются частью контракта? В аналогии с программными API, структура ответа API является контрактом. Качество и надежность ("время безотказной работы") также являются очень важными атрибутами качества API, но они не являются частью контракта как такового. Когда контракт изменяется в обратной несовместимой манере, это является критическим изменением, требующим увеличения основной версии.

Нужно ли определять каждый столбец для контракта?

В настоящее время контракты dbt применяются ко всем столбцам, определенным в модели, и требуют явного указания ожиданий относительно всех этих столбцов. Явное объявление контракта не является случайностью — это очень важная часть этой функции.

В то же время, для моделей с множеством столбцов, мы понимаем, что это может означать много yaml. Мы исследуем возможность поддержки "выведенных" контрактов. Это позволит вам определять ограничения и строгую типизацию данных для подмножества столбцов, при этом все еще обнаруживая критические изменения на других столбцах, сравнивая с той же моделью в производстве. Это не то же самое, что "частичный" контракт, потому что все столбцы в модели все еще проверяются во время выполнения и сопоставляются с тем, что определено явно в вашем yaml-контракте или неявно с состоянием сравнения. Если вас интересует "выведенный" контракт, пожалуйста, проголосуйте или оставьте комментарий на dbt-core#7432.

Как обрабатываются критические изменения?

При сравнении с предыдущим состоянием проекта dbt будет искать критические изменения, которые могут повлиять на потребителей в дальнейшем. Если обнаружены критические изменения, dbt выдаст ошибку контракта.

К критическим изменениям относятся:

  • Удаление существующего столбца
  • Изменение типа данных существующего столбца
  • Удаление или изменение одного из constraints на существующем столбце (dbt версии 1.6 или выше)
  • Удаление модели с контрактом путем ее удаления, переименования или отключения (dbt v1.9 или выше).
    • модели с версией вызовут ошибку. модели без версии вызовут предупреждение.

Более подробная информация доступна в справочнике по контрактам.

0