dbtの開発を楽にしてくれるパッケージ「codegen」
前にcodegenを使ったような?使ってなかったような??
記憶が曖昧ですが、真面目に使い方を確認したことが無いので、この機に触ってみたいと思います。
codegen
マクロを使ってYAMLファイルやベースモデルのSQLをいい感じに自動作成してくれるみたいです。
packages.ymlの設定
packages.ymlにcodegenを使えるよう設定します。
packages:
- package: dbt-labs/codegen
version: 0.11.0
その後、dbt deps
コマンドでパッケージをインストールします。
codegenに用意されているマクロたち
- マクロ
generate_source
名前のとおり、sourceのYAMLファイルの中身を生成して出力してくれます。
引数のschema_nameがsourcesのnameとして出力されます。
dbt run-operation generate_source --args '{"schema_name": "PUBLIC", "database_name": "DEMO_DB", "table_names":["CUSTOMERS", "ORDERS"]}'
01:58:05 Running with dbt=1.6.1
01:58:06 Registered adapter: snowflake=1.6.2
01:58:06 Found 5 models, 3 seeds, 8 tests, 0 sources, 0 exposures, 0 metrics, 617 macros, 0 groups, 0 semantic models
01:58:06 version: 2
sources:
- name: public
tables:
- name: customers
- name: orders
create_base_models
create_base_modelsはベースモデルを作成するスクリプトを生成するマクロです。
dbt run-operation codegen.create_base_models --args '{source_name: public, tables: ["stg_orders"]}'
03:22:27 Running with dbt=1.6.1
03:22:28 Registered adapter: snowflake=1.6.2
03:22:28 Found 5 models, 3 seeds, 8 tests, 3 sources, 0 exposures, 0 metrics, 502 macros, 0 groups, 0 semantic models
03:22:28 Run these commands in your shell to generate the models:
source dbt_packages/codegen/bash_scripts/base_model_creation.sh public raw_orders
base_model_creation
create_base_modelsを実行して生成されたスクリプトを実行します。
source dbt_packages/codegen/bash_scripts/base_model_creation.sh public raw_orders
を実行すると、models配下に「stg_public__raw_orders.sql」が作成され、中身は以下の通りです。
[0m03:23:52 Found 7 models, 3 seeds, 8 tests, 3 sources, 0 exposures, 0 metrics, 502 macros, 0 groups, 0 semantic models
[0m03:23:54
with source as (
select * from {{ source('public', 'raw_orders') }}
),
renamed as (
select
id,
user_id,
order_date,
status
from source
)
select * from renamed
このSQファイルのままdbt runを実行しても失敗します。
なので、スクリプトを修正してSQLファイルの不要な先頭行を削除します。
#!/bin/bash
echo "" > models/stg_$1__$2.sql
dbt run-operation codegen.generate_base_model --args '{"source_name": "'$1'", "table_name": "'$2'"}' | tail -n +5 >> models/stg_$1__$2.sql
これで再度source dbt_packages/codegen/bash_scripts/base_model_creation.sh public raw_orders
を実行すればOK。
generate_base_model
ベースモデルを生成するマクロです。
コマンド見ればわかりますが、dbt_packages/codegen/bash_scripts/base_model_creation.shと同じコマンドを実行しているだけです。
標準出力するか、ファイルとして保存するかの違いですね。
dbt run-operation generate_base_model --args '{"source_name": "public", "table_name": "raw_orders"}'
03:58:35 Running with dbt=1.6.1
03:58:36 Registered adapter: snowflake=1.6.4
03:58:36 Found 6 models, 3 seeds, 8 tests, 3 sources, 0 exposures, 0 metrics, 502 macros, 0 groups, 0 semantic models
03:58:38
with source as (
select * from {{ source('public', 'raw_orders') }}
),
renamed as (
select
id,
user_id,
order_date,
status
from source
)
select * from renamed
generate_model_yaml
モデルのYAMLを出力するマクロです。
これ正直osmosisでいい気がする・・・
dbt run-operation generate_model_yaml --args '{"model_name": "raw_customers"}'
02:24:41 Running with dbt=1.6.1
02:24:42 Registered adapter: snowflake=1.6.2
02:24:42 Found 5 models, 3 seeds, 8 tests, 3 sources, 0 exposures, 0 metrics, 617 macros, 0 groups, 0 semantic models
02:24:44 version: 2
models:
- name: raw_customers
description: ""
columns:
- name: id
description: ""
- name: first_name
description: ""
- name: last_name
description: ""
generate_model_import_ctes
これはCTE風にSQLを生成してくれるマクロです。
これの使い方がよく分からなかったです。パッと見CTEで書けていないクエリをCTEE風に書き直したクエリを出力してくれると思ったけど、違った。
jaffle shopのモデルを試しに食わせてみたら、若干違うクエリが出力されました。
最終的なアウトプットのデータ構造は同じでした。
使い所が限られてそうですが、便利なマクロです。
dbt run-operation generate_model_import_ctes --args '{"model_name": "customers"}'
02:34:27 Running with dbt=1.6.1
02:34:27 Registered adapter: snowflake=1.6.2
02:34:28 Unable to do partial parsing because a project config has changed
02:34:30 Found 5 models, 3 seeds, 8 tests, 3 sources, 0 exposures, 0 metrics, 502 macros, 0 groups, 0 semantic models
02:34:30 with stg_customers as (
select * from {{ ref('stg_customers') }}
),
stg_orders as (
select * from {{ ref('stg_orders') }}
),
stg_payments as (
select * from {{ ref('stg_payments') }}
),
customers as (
select * from stg_customers
),
orders as (
select * from stg_orders
),
payments as (
select * from stg_payments
),
customer_orders as (
select
customer_id,
min(order_date) as first_order,
max(order_date) as most_recent_order,
count(order_id) as number_of_orders
from orders
group by customer_id
),
customer_payments as (
select
orders.customer_id,
sum(amount) as total_amount
from payments
left join orders
on
payments.order_id = orders.order_id
group by orders.customer_id
),
final as (
select
customers.customer_id,
customers.first_name,
customers.last_name,
customer_orders.first_order,
customer_orders.most_recent_order,
customer_orders.number_of_orders,
customer_payments.total_amount as customer_lifetime_value
from customers
left join customer_orders
on customers.customer_id = customer_orders.customer_id
left join customer_payments
on customers.customer_id = customer_payments.customer_id
)
select * from final
Discussion