dbt jinja テンプレートエンジンの基礎構文について調べてみた
こんにちは!よしななです。
今回は、dbt jinja テンプレートエンジンの基礎構文について実際に自分の手元で触って挙動を確かめたので、備忘録として残します。
目次
- 前提
- jinja とは
- jinja の基礎構文
- 変数の代入と参照
- if 構文
- for 構文
- まとめ
- 参考文献
前提
本ブログのコードは以下の環境で実行しています。
- OS
- Windows 11
- ターミナル
- VSCode / PowerShell で実行
本ブログのコードを実行するには、以下の準備が必要です。
今回は、以下の準備がすべて完了した前提で進めます。
- 環境セットアップ
- dbt-core インストール
- AWS Athena と dbt-core は接続済み
dbt init
コマンドを実行し、dbt モデルを格納するフォルダtest_jinja
を作成-
データの準備
- Kaggle - Rossmann Store Sales の train.csv を使用しています
- Amazon Athena で train.csv をもとに以下の DDL 文を実行しています。
CREATE EXTERNAL TABLE `test_jinja`( `store` int, `dayofweek` int, `date` date, `sales` int, `customers` int, `open` int, `promo` int, `stateholiday` int, `schoolholiday` int) ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION "{train.csv を格納している S3 バケット名}" TBLPROPERTIES ( 'classification'='csv', 'columnsOrdered'='false', 'compressionType'='none', 'delimiter'=',', 'skip.header.line.count'='1', 'transient_lastDdlTime'='1717037230')
dbt init
実行で作成したtest_jinja
プロジェクト配下に dbt モデル:test_jinja_01.sql
を作成します。test_jinja_01.sql
に dbt モデルのロジックを書いていきます。
jinja とは
jinja とは、Python で開発されたテンプレートエンジンの一種で、HTML や CSS など様々なテキストファイルの記述に用いられます。
dbtでは、SQL と jinjaを組み合わせることができ、dbt プロジェクト内で SQL の機能を強化・拡張するためのツールとして機能します。
jinja を用いて dbt でできることについて、次項で説明します。
jinja の基礎構文
- {{ ... }}:式
- 式の結果を文字列として出力します。
- 式を使用して変数を参照したり、dbt macros を呼び出したりすることができます。
- {% ... %}:制御構文
- for ループや if 文の設定、変数の設定や変更、マクロの定義など、フローの制御に使用します。
- {# ... #}:コメント
- dbt モデルとして実行しないコメントなどを挿入する場合に使用します。
変数の代入と参照
Jinja の中で変数を代入する場合は{%- set -%}
を使用し、変数を参照する場合は{{ 変数名 }}
を入力します。
以下の dbt モデル:test_jinja_01
では{%- set -%}
でmy_var
を変数として定義し、jinja
を代入しています。
{{ my_var }}
部分で変数を参照し、test_jinja
テーブルとしてselect * from
で参照されるようにしています。
{%- set my_var = 'jinja' -%} select * from test_{{ my_var }}
Athena での実行結果
dbt モデル:test_jinja_01 が起動し、select * from test_jinja
が実行できました。
if 構文
jinja の if 構文を使用することにより、{% if "{条件式}" %}
部分で指定した条件によって処理を分岐させることができます。
例えば、以下のprofiles.yml
内のtarget: prod
部分を変更することで、jinja 側でtarget.name
を変更することができます。
profiles.yml
に応じてデータを保存するデータソースを動的に切り替えることが可能です。
profiles.yml
test_jinja: outputs: target: prod prod: database: awsdatacatalog region_name: ap-northeast-1 s3_data_dir: "{指定したS3 フォルダ名}" s3_staging_dir: "{指定したS3 フォルダ名}" schema: "{Athena に保存したデータベース名}" threads: 1 type: athena
profiles.yml
内のtarget.name
で指定された変数の値を判定します。
target.name== 'prod'
の場合とそうでない場合で処理を分岐させることが可能です。
{% if target.name == 'prod' %} select store dayofweek date from test_jinja {% else %} select sales customers from test_jinja {% endif %}
Athena での実行結果
profiles.yml
のtarget.name
でprod
を指定しているため、
{% if target.name == 'prod' %}
~以降のselect
句が生成されていることを実行結果から確認できました。
for 構文
jinja の for 構文は、データの繰り返し処理を行う際に使用します。
例えば、以下のようにset
でsource_columns
変数にテーブルの列名を格納し、Jinja のループ処理を使用して動的にselect
句を生成しています。
{% set source_columns = ["store", "dayofweek", "date", "sales", "customers", "open", "promo", "stateholiday", "schoolholiday"] %} select {% for col in source_columns %} {{ col }}{% if not loop.last %}, {% endif %} {% endfor %} from test_jinja
Athena での実行結果
source_columns
にセットしたカラム名をループ処理して、select
句を生成していることが実行結果から確認できました。
for 構文で使用可能な変数について
loop 変数を使用し、繰り返し処理の制御が可能です。
今回の例ではloop.last
を使用し、source_columns
に入れたリストをすべて繰り返して処理を行っています。
変数名 | 説明 |
---|---|
loop.index | 何ループ目か返します(1始まり) |
loop.index0 | 何ループ目か返します(0始まり) |
loop.revindex | あと何ループか返します(1始まり) |
loop.revindex0 | あと何ループか返します(0始まり) |
loop.first | 最初のループのときは true を返します |
loop.last | ループの最後のときに true を返します |
loop.length | 何回ループするのか返します |
まとめ
jinja の構文については以上となります。
次の記事でdbt 組み込み jinja 関数について手元で実行した結果と調査した挙動について紹介できればと思います。
ここまで読んでいただきありがとうございました!