DBT
January 3, 2024

Установка dbt в Windows и создание первого проекта.

Устанавливал с помощью pip, виртуальное окружение не использовал, так что нужны прописанные в окружении системные переменные. У меня установлена Anaconda, так что системные переменные выглядят так:

Переменные среды

1) Запуск cmd от имени администратора pip install dbt-core

Была установлена самая актуальная (на момент написания заметки) версия. Её можно понизить или понизить, указав версию в команде (в следующей команде понизили dbt-core до версии 1.5)

pip install --upgrade dbt-core==1.5

2) После успешной установки устанавливаем коннектор к PostgreSQL.

pip install dbt-postgres

Для установки коннектора к, например, Clickhouse команда была бы pip install dbt-clickhouse

При необходимости установленный коннектор впоследствии можно будет апгрейдить командой

pip install --upgrade dbt-ADAPTER_NAME

3) Проверяем установку командой dbt --version, видим, что всё ок.

4) Запуск настройки проекта командой (рисунок ниже) dbt init kimball_pr (kimball_pr - название учебного проекта), указываем СУБД, которую будем использовать - у нас это единственный вариант (т.к. установлен только 1 коннектор). И указываем реквизиты доступа к PostgreSQL. Это потом можно увидеть в файле profiles.yml, о котором возможно расскажу далее.

Настройка проекта

5) По рекомендации в последнем сообщении Profile kimball_pr written to C:\Users\Дом\.dbt\profiles.yml using target's profile_template.yml and your supplied values. Run 'dbt debug' to validate the connection запускаем проверку.

Видимо, всё ок.

6) Запускаем созданный проект.

В итоге смотрим, что в выбранной при настройке проекта БД de101 в схеме kimball появились представление и таблица с соответствующими названиями.

А у нас появилась папка с проектом: c:\IT_Learning\dbt_proj\kimball_pr\ (на самом деле она появилась при выполнении dbt init, но не суть).

DBT успешно установлен и первый проект готов.

Вид проекта dbt в VS Code

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

Данные брал отсюда https://github.com/Data-Learn/data-engineering/blob/master/DE-101%20Modules/Module02/DE%20-%20101%20Lab%202.1/readme.md - спасибо Диме Аношину и его бесплатному курсу https://datalearn.ru/

Я уже создал в схеме stg таблицу-источник stg.orders для наших таблиц измерений и фактов. Теперь просто можно брать куски кода тут https://github.com/Data-Learn/data-engineering/blob/master/DE-101%20Modules/Module02/DE%20-%20101%20Lab%202.1/from_stg_to_dw.sql и вставлять в файлы моделей.

Создадим пару новых моделей и запустим проект.

Определения новых моделей
Запуск проекта.

Видно, что теперь у нас 4 модели, создано ещё 2 view в указанной схеме.

Новые вью

Возможно, вы спросите: "почему новые объекты создаются как view, а не таблицы?" Ответ прост: если в файле модели не указана в явном виде материализация, то её тип берётся из файла dbt_project.yml

dbt_project.yml

Давайте создадим модель в табличку.

Новая модель

После прогона видим новую таблицу

Новая таблица в схеме

В реальности вряд ли вы будете запускать весь проект целиком.

Отдельные модели можно запускать, используя ключ models.

dbt run --models geo_dim

Если нужно запустить более 1 модели, названия разделяются запятой. Если в конфиге модели указан таг, можно запустить все модели с этим тагом.

Например, в модели указаны следующие таги

{{ config(
        materialized='table',
        tags=['core_layer', 'task1']
    ) }}  

Тогда все модели с тагом 'core_layer' можно запустить следующей командой:

dbt run --select "tag:core_layer"

При этом желательно в моделях явно прописывать названия моделей, от которых они зависят. Например, если модель model3 должна собираться после моделей model1 и model2, от которых она зависит, эту зависимость в файле model3.sql можно прописать так:

-- depends_on: {{ ref('model1') }}
-- depends_on: {{ ref('model2') }}

Окей, удалю модели из демо, добавлю ещё 2 таблички измерений и везде поставлю материализацию в табличку. Код модели для сбора таблицы фактов ниже.

{{ config(materialized='table') }}
select
	 100+row_number() over() as sales_id
	 ,cust_id
	 ,to_char(order_date,'yyyymmdd')::int as  order_date_id
	 ,to_char(ship_date,'yyyymmdd')::int as  ship_date_id
	 ,product_dim.prod_id
	 ,shipping_dim.ship_id
	 ,geo_id
	 ,o.order_id
	 ,sales
	 ,profit
     ,quantity
	 ,discount
from stg.orders o 
inner join {{ ref('shipping_dim') }} 
  on o.ship_mode = shipping_dim.ship_mode
inner join {{ ref('geo_dim') }}  
  on o.postal_code = geo_dim.postal_code 
  and geo_dim.country=o.country 
  and geo_dim.city = o.city 
  and o.state = geo_dim.state --City Burlington doesn't have postal code
inner join {{ ref('product_dim') }}
  on o.product_name = product_dim.product_name 
  and o.segment=product_dim.segment 
  and o.subcategory=product_dim.subcategory 
  and o.category=product_dim.category 
  and o.product_id=product_dim.product_id 
inner join {{ ref('customer_dim') }}  
  on customer_dim.customer_id=o.customer_id 
  and customer_dim.customer_name=o.customer_name

Финальный прогон проекта.

Финальный прогон

Итого, после успешного выполнения dbt run имеем 5 табличек измерений и 1 табличку фактов. Проект завершён.

Схема kimball, таблицы

P.S. Сделано на Windows 10 и Python 3.9.13

P.P.S. В реальном проекте модели скорее всего будут выглядеть более мудрёно, чем в учебном проекте. Будут и переменные, и макросы, и шаблоны jinja. P.P.P.S.Увидеть, как выглядит финальный селект, сгенерированный моделью, можно в папке на рисунке ниже.