dbt exposures на собеседовании Data Engineer

Проверь себя · 1/3разбор после ответа
Как удобнее интерпретировать дерево EXPLAIN, чтобы понять, откуда берутся строки и где тратятся ресурсы запроса?

Зачем нужны exposures

Exposure в dbt — это декларация внешнего потребителя ваших моделей: дашборда, ML-модели или приложения, которое читает данные из витрины. Проблема, которую он решает, простая: обычный dbt-граф обрывается на последней модели, и по нему не видно, что происходит с данными дальше. Когда аналитик спрашивает «а что сломается, если я перепишу fct_orders?» — без exposures ответа нет, потому что dbt не знает про дашборды и отчёты за пределами проекта.

Exposure не материализуется в базе — это чисто метаданные. Но в dbt docs и в графе lineage он появляется как финальный узел, замыкающий цепочку «источник → staging → витрина → потребитель».

# models/exposures.yml
exposures:
  - name: weekly_revenue_dashboard
    type: dashboard
    maturity: high
    url: https://datalens.yandex.ru/...
    owner:
      name: Marketing Team
      email: marketing@company.ru
    depends_on:
      - ref('fct_orders')
      - ref('dim_customers')

На собесе DE это спрашивают в контексте data quality и владения данными: интервьюер проверяет, понимаете ли вы, как довести lineage до реального потребителя и как заранее понять, кого затронет ваше изменение.

Как описать exposure

Exposure объявляется в YAML и описывает потребителя набором полей. Ключевые из них:

  • name — уникальное имя потребителя, по нему exposure выбирается в командах dbt.
  • type — категория потребителя. Допустимые значения: dashboard, notebook, analysis, ml, application. Влияет на иконку и группировку в docs.
  • owner — имя и email ответственной команды. Именно к нему обращаются, когда модель ниже по потоку ломается.
  • depends_on — список моделей и источников через ref() и source(), от которых зависит потребитель. Это и есть связь, по которой строится lineage.
  • url и description — ссылка на сам дашборд и пояснение, чтобы человек в docs понял, что это и зачем.
  • maturity — необязательный признак зрелости (high / medium / low), помогает отделить продовые дашборды от экспериментов.

Польза для lineage

Главная ценность exposures — impact-анализ. В сгенерированной документации (dbt docs generate) потребитель виден как финальная нода графа, и от любой модели можно проследить, какие дашборды и ML-модели её используют.

fct_orders (model)
  └─ exposed by: weekly_revenue_dashboard (Marketing Team)

Практический смысл: перед тем как менять схему или логику fct_orders, инженер видит, что от неё зависит дашборд маркетинга, и знает, кого предупредить о breaking change. Без exposures это знание живёт только в головах и всплывает уже после того, как у кого-то сломался отчёт.

Готовишься к собесу Data Engineer?
Spark, Airflow, ClickHouse, SQL для DE — вопросы с разборами в Telegram
Тренировать DE в Telegram

Применение в CI

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

# посмотреть, что стоит за конкретным дашбордом
dbt ls --select +exposure:weekly_revenue_dashboard

# пересобрать и протестировать всё, от чего зависит дашборд
dbt build --select +exposure:weekly_revenue_dashboard

Оператор + перед селектором подтягивает все апстрим-модели потребителя. В связке со Slim CI (сборка только изменённого через state:modified) это даёт точечную проверку: если PR трогает модель, от которой зависит продовый дашборд, пайплайн прогонит именно эту ветку графа и упадёт до мержа, если что-то не проходит тесты. Так breaking change отлавливается на этапе ревью, а не в проде.

Частые ошибки

Считать, что exposures создаются сами. dbt их не генерирует автоматически — их пишут и поддерживают руками. Если о новом дашборде забыли, в lineage его не будет, и impact-анализ соврёт.

Оставлять exposures протухшими. Дашборд удалили, а exposure остался — граф показывает несуществующего потребителя. Их нужно ревьюить вместе с моделями.

Путать exposure с моделью. Exposure ничего не материализует в БД и не выполняет SQL. Это метаданные о потребителе, а не таблица.

Не заполнять owner. Без владельца теряется главный смысл — некого предупредить при изменении. Exposure без контакта ответственного почти бесполезен.

Связанные темы

FAQ

Чем exposure отличается от source и модели?

source описывает входные данные на входе в проект, модель — трансформацию внутри, а exposure — потребителя на выходе. Все три участвуют в lineage, но source и модели материализуются или читаются из БД, а exposure — только метаданные, замыкающие граф на дашборде или ML-модели.

Как понять, какие дашборды сломает изменение модели?

Через селектор dbt ls --select model_name+ можно вывести всё, что стоит ниже по потоку, включая exposures-потребителей. В CI это же используют, чтобы прогнать тесты именно по затронутой ветке. Именно ради такого impact-анализа exposures и заводят.

Проверяет ли dbt, что дашборд действительно работает?

Нет. dbt не ходит в BI-инструмент и не знает, жив ли дашборд. Exposure лишь фиксирует зависимость и владельца. Проверять «живость» самого дашборда — задача BI-платформы или отдельного мониторинга; dbt отвечает только за данные под ним.

Что писать в поле type для ML-модели?

Тип ml. Он подходит, когда витрину читает обучающий пайплайн или сервис инференса. Это помогает в docs отделить ML-потребителей от обычных дашбордов и понимать, что за изменением данных стоит переобучение модели, а не просто пересбор отчёта.

Это официальная информация?

Нет. Статья основана на документации dbt (версии 1.7+) и типовых практиках. Конкретные требования зависят от компании и уровня позиции.


Тренируйте Data Engineering — откройте тренажёр с 1500+ вопросами для собесов.