Welcome to my personal place for love, peace and happiness❣️

Нет, инженерам по обработке данных не НУЖЕН dbt

Оригинал: https://blog.det.life/no-data-engineers-dont-need-dbt-30573eafa15e

Нужно ли мне изучать dbt? Я часто вижу этот вопрос на Reddit, и он меня путает. Звучит просто. Использует ли ваша компания dbt? Если да, то да. Если нет, то нет. Как и любой другой инструмент, dbt лучше всего использовать в тех сценариях, где он хорошо подходит. В то же время, я часто читаю мнения людей, которые говорят, что dbt не приносит пользы. Затем они начинают перечислять десять инструментов, которые они используют вместо этого. Должен быть какой-то средний путь.

Видите ли, здесь важен именно аспект «хорошей подгонки», а не необходимость. Мы используем инструменты для решения проблем. Позвольте повторить это. Мы используем инструменты для решения проблем. Не потому, что они крутые или мы хотим добавить их в наш набор навыков, или потому что все остальные их используют. Инструменты помогают нам решать проблемы. Давайте рассмотрим проблемы, которые помогает решать dbt, и случаи, когда он подходит. Черт возьми. Давайте также поговорим о сценариях, в которых он не подходит.

Что такое dbt — лучшее определение?
Существует распространенное заблуждение, что dbt — это инструмент ELT, который позволяет извлекать, загружать и преобразовывать данные. Это неверно. Dbt — это всего лишь инструмент для преобразования данных с использованием SQL. Если вы не используете SQL для преобразования данных, использование dbt станет огромным изменением. Возможно, это не для вас. Если у вас есть хранилище данных, где SQL является общим языком, то dbt может быть хорошим вариантом.

Говорить, что dbt — это просто инструмент для преобразования, недооценивает его ценность, потому что преобразование данных — это большая задача в корпоративной среде. Так что давайте дадим ему лучшее определение:
Dbt — это набор утилит, который позволяет управлять преобразованием данных с использованием динамического SQL в гибком языке шаблонов.

Это уже получше, хотя я не уверен, как бы это восприняли в отделе маркетинга dbt Labs. Проблема в том, что это определение говорит нам, что делает dbt, но не объясняет, как он это делает или какие проблемы он решает. Чтобы уточнить определение, давайте обсудим некоторые проблемы, возникающие при преобразовании данных. В частности, давайте обсудим четыре ключевые проблемы, с которыми мы все сталкиваемся.

Управление зависимостями
Динамический код
Материализация
Тестирование – качество данных и проверка кода
Генерация документация ( плюс от меня )

Управление зависимостями
Прежде чем мы напишем строчку SQL, мы должны знать исходные данные для наших таблиц и представлений. Это очевидно, верно? Если мы выбираем столбцы, мы должны знать, откуда мы выбираем. Это включает в себя базу данных, схему и таблицу. Таблица обычно, но не всегда, статична. Однако база данных и схема часто меняются в разных средах. Например, у нас могут быть рабочие, промежуточные и производственные среды, использующие разные базы данных.

Не большая проблема для решения, но самодельные решения будут нуждаться в реализации какой-то системы управления зависимостями. Dbt делает это с помощью функции ref(). Вот пример того, как это работает у меня на работе. Если я использую ref() в WHERE clause, dbt автоматически подберет нужную таблицу для среды, в которой мы работаем.

dev: dev_lgodin_dw.common.date_d
staging: dw_staging.common.date_d
prod: dw.common.date_d

```sql
select
date,
year,
month
from {{ ref(‘date_d’) }}
```

Управление зависимостями – это гораздо больше, чем просто идентификация полностью квалифицированного имени таблицы. Мы должны понимать порядок выполнения преобразований. Например, fact_sales должна выполняться перед fact_sales_monthly. Использование ref() автоматически решает эту задачу. Фактически, dbt создает граф зависимостей каждый раз при его запуске. Посмотрите на зависимости ниже для dbt-fake.

Граф зависимостей dbt

Давайте надеяться, что вы никогда не увидите что-то подобное в вашем хранилище данных. Я использую это для создания фальшивых данных, поэтому это не типичный сценарий. Используя ref() в моих моделях, dbt фиксирует зависимости за меня. Он выполнит эти модели в четыре этапа, используя параллелизм, когда это возможно.

fake_companies, fake_dates и fake_numbers
companies_base
employees_base
enterprise_orders_base

Теперь представьте хранилище данных с сотнями источников и сотнями моделей. Ручное определение зависимостей было бы непростой задачей. Вам понадобилась бы какая-то утилита для управления зависимостями. Dbt решает эту задачу из коробки. Если вы хотите пойти дальше, вы можете изучить зависимости с помощью переменной graph или manifest.json в dbt.

Динамический SQL
```sql
{{
config(
materialized = ‘incremental’,
unique_key = [‘order_date’, ‘user_id’, ‘product_id’],
)
}}

select
date as order_date,
user_id,
product_id,
num_items,
sum(num_items) over (partition by user_id) as total_weekly_items,
current_timestamp() as created_at,
current_timestamp() as updated_at
from {{ get_date_filtered_subquery(
source_model=ref(‘stg_orders’),
target_model=this,
run_at_date=get_run_at_date()) }}
```

Моя главная жалоба на SQL заключается в его слабой поддержке для написания динамических запросов. Каждый поставщик реализует свои собственные методы для динамической генерации SQL путем склеивания строк и запуска некоторых команд exec. Dbt интегрирует Jinja-SQL как часть комплексного пакета для преобразования данных. Это значит, что мы можем писать динамический SQL на языке шаблонов.

Хотели ли вы когда-нибудь использовать цикл for в SQL для написания повторяющегося кода? Вы можете сделать это. Я часто использую метаданные для генерации больших запросов. Например, у нас есть таблица Customer 360 с ~200 столбцами. Эта таблица строится динамически с использованием CSV для метаданных и Jinja для генерации SQL. Это не только экономит время, но и значительно уменьшает количество ошибок, вызванных ручным вводом.

Как насчет автоматизации логики дат в ваших преобразованиях? Да, динамический SQL спасает положение. Нужно ли запускать ваши задания для конкретных дат, возможно, для обеспечения идемпотентности? Dbt поможет. Суть в том, что SQL хорош, но динамический SQL позволяет писать запросы, как программист. С Jinja мы можем создавать переиспользуемые компоненты, называемые макросами. Мы можем использовать циклы для написания повторяющегося кода. Мы можем думать о SQL как о результате нашей работы, а не только об усилиях.

Автоматическая Материализация

Самое распространенное, что мы делаем в хранилищах данных, — это создаем/обновляем таблицы и представления. Dbt называет это материализацией. Обычно мы используем insert или merge для этого. Хотя эти операторы не сложны, они быстро становятся утомительными. Мы находим себя пишущими один и тот же код снова и снова, просто чтобы записать разные столбцы в базу данных. Какое это пустая трата времени.

С dbt нам никогда не нужно писать операторы insert или merge. Мы пишем запросы и настраиваем материализацию. Хотите представление (view)? materialization = ‘view’. Это инкрементальная таблица? Правильно, materialization = ‘incremental’. Может быть, вам нужна медленно меняющаяся размерность типа-2? Это немного другое, но dbt имеет для этого “снимки” (snapshots). Когда все сказано и сделано, мы настраиваем, как мы хотим материализовать данные, и dbt автоматически обрабатывает это. Это мощно. Давайте посмотрим на пример. Код ниже реализует инкрементальную таблицу.

```sql
{{
config(
materialized = ‘incremental’,
unique_key = [‘order_date’, ‘user_id’, ‘product_id’],
)
}}

select
date as order_date,
user_id,
product_id,
num_items,
sum(num_items) over (partition by user_id) as total_weekly_items,
current_timestamp() as created_at,
current_timestamp() as updated_at
from {{ get_date_filtered_subquery(
source_model=ref(‘stg_orders’),
target_model=this,
run_at_date=get_run_at_date()) }}
```

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

```sql
create or replace table `leogodin217-dbt-tutorial`.`enterprise_sales`.`weekly_orders`
OPTIONS()
as (
select
date as order_date,
user_id,
product_id,
num_items,
sum(num_items) over (partition by user_id) as total_weekly_items,
current_timestamp() as created_at,
current_timestamp() as updated_at
from (
select
*
from `leogodin217-dbt-tutorial`.`enterprise_sales`.`stg_orders`
) as stg_orders
);
```

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

```sql
merge into `leogodin217-dbt-tutorial`.`enterprise_sales`.`weekly_orders` as DBT_INTERNAL_DEST
using (
select
date as order_date,
user_id,
product_id,
num_items,
sum(num_items) over (partition by user_id) as total_weekly_items,
current_timestamp() as created_at,
current_timestamp() as updated_at
from (
select
*
from `leogodin217-dbt-tutorial`.`enterprise_sales`.`stg_orders`
where date between ‘2024-07-07’ and ‘2024-07-13’
) as stg_orders
) as DBT_INTERNAL_SOURCE
on (
DBT_INTERNAL_SOURCE.order_date = DBT_INTERNAL_DEST.order_date
) and (
DBT_INTERNAL_SOURCE.user_id = DBT_INTERNAL_DEST.user_id
) and (
DBT_INTERNAL_SOURCE.product_id = DBT_INTERNAL_DEST.product_id
)

when matched then update set
`order_date` = DBT_INTERNAL_SOURCE.`order_date`,
`user_id` = DBT_INTERNAL_SOURCE.`user_id`,
`product_id` = DBT_INTERNAL_SOURCE.`product_id`,
`num_items` = DBT_INTERNAL_SOURCE.`num_items`,
`total_weekly_items` = DBT_INTERNAL_SOURCE.`total_weekly_items`,
`created_at` = DBT_INTERNAL_SOURCE.`created_at`,
`updated_at` = DBT_INTERNAL_SOURCE.`updated_at`

when not matched then insert
(`order_date`, `user_id`, `product_id`, `num_items`, `total_weekly_items`, `created_at`, `updated_at`)
values
(`order_date`, `user_id`, `product_id`, `num_items`, `total_weekly_items`, `created_at`, `updated_at`)
```

Тестирование. Раз, два, три, тестирование.

Не секрет, что хранилища данных отстают на световые годы от традиционной разработки программного обеспечения в плане тестирования. Существуют множество причин для этого. Во-первых, тестировать хранилища данных на порядки сложнее, чем общее ПО. В Python-приложении мы можем выделить отдельный модуль. Это не применимо в хранилище данных. Нам всегда нужна работающая база данных для тестирования чего-либо. В лучшем случае у нас есть интеграционные или системные тесты. Более того, помимо тестирования нашего кода, нам нужно тестировать сами данные. Это не часто входит в область ответственности разработчиков приложений. Как dbt справляется с этим?

Качество данных

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

Валидация кода

Существуют и другие типы тестов. Важно отметить, что тесты качества данных проверяют данные и зависят от входящих источников. Мы не можем тестировать крайние случаи, если они не включены в наши данные. Проверка качества данных касается данных, но не гарантирует, что наш код корректен. Здесь на помощь приходит валидация кода.

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

Финальное определение для dbt

Мы обсудили четыре ключевые проблемы, с которыми сталкиваемся при преобразовании данных и как dbt решает их. У dbt есть много других функций, и стоит посетить их веб-сайт для получения дополнительной информации. Там вы найдете больше о контроле версий, документации, графических операторах для запуска подмножеств моделей и многое другое. Но мы знаем достаточно, чтобы улучшить наше определение.

Что такое dbt?
Dbt — это комплексный пакет, позволяющий инженерам сосредоточиться на реализации бизнес-логики в преобразованиях хранилища данных.

Как работает dbt?
Dbt работает, абстрагируя общие шаблоны хранилищ данных в автоматизацию, управляемую конфигурацией, и предоставляя набор инструментов для упрощения SQL-преобразований, тестов и документации.

Когда dbt вам не нужен

Не существует единого инструмента, который подошел бы всем. Мы говорили об этом. Мы используем инструменты для решения проблем. Dbt не решает все проблемы. В каких случаях dbt не является правильным инструментом для работы?

  • У вас уже есть зрелая платформа. Хранилища данных существуют намного дольше, чем dbt. Многие компании создали фантастические среды для преобразований. Эти инженеры не нуждаются в новых инструментах.
  • Вы используете ETL вместо ELT. Я знаю, что сейчас ELT в моде, но есть много примеров, когда ETL лучше подходит. Если это ваш рабочий процесс, то dbt не поможет. Dbt только преобразует данные. Он не будет перемещать данные с S3 в Snowflake. Он не будет читать из MongoDB и записывать в Postgres. Это не его задача.( До тех пор пока у вас нет Trino )
  • Ваша рабочая нагрузка не принадлежит хранилищу данных. Некоторые источники данных не вписываются в простой ELT-паттерн. Cai Perry-Jones написал пример с сотнями файлов CSV с разными схемами. Модели Python в dbt, конечно, могут справиться с этим, но возможно, лучше сделать это до того, как данные попадут в ваше хранилище данных. Конечно, как только они попадут туда, dbt может быть правильным инструментом для интеграции этих данных в нижележащие таблицы и представления.

Хотите лучше понять dbt? Попробуйте мой список статей по промежуточному и продвинутому уровню dbt.

Нужен ли вам dbt?

Надеюсь, к этому моменту вы поняли, что мы все время задавали неправильный вопрос. Никому не нужен dbt, если это не требуется для их работы. Гораздо лучше задать вопрос: поможет ли dbt решить проблемы, с которыми мы сталкиваемся? Если dbt делает вашу работу проще, то, вероятно, это хороший выбор. Dbt помог нам улучшить качество данных, уменьшить количество сбоев задач и улучшить нашу дисциплину разработки программного обеспечения. По этим причинам он хорошо подходит для нас. Нам не нужен dbt, но он, безусловно, решает множество проблем.

Follow this blog
Send
Share