![[ver1.5新機能]対象のモデルのデータ型や制約が定義通りであるか保証できる「Contracts」を試してみた](https://devio2023-media.developers.io/wp-content/uploads/2022/03/dbt-1200x630-1.jpg)
[ver1.5新機能]対象のモデルのデータ型や制約が定義通りであるか保証できる「Contracts」を試してみた
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
さがらです。
先日、dbt-coreのver1.5がリリースされました。
dbt-core ver1.5の新機能として、「Contracts」がリリースされました。この機能を試してみたので、本記事で試した内容をまとめてみます。
Contractsとは
一言でいうと、対象のモデルのデータ型や制約が定義通りであるか保証できる機能です。
dbtは基本的に定義されたSELECT文が返す結果に応じて、カラム名とデータ型を自動で決めてくれますが、ソースデータの仕様変更などの影響でデータ型が勝手に変わってしまうことなどが起こり得ます。
勝手にデータ型が変わると、後続のdbtのモデルが上手く動かなくなったり、BIツールで対象のモデルから出力されたテーブルを参照するダッシュボードが壊れてしまったり、いろんなトラブルに繋がる可能性があります。
そんなときに役立つのが、今回の新機能「Contracts」です!
dbt上で事前に各モデルが出力するカラムに対してdata_typeやconstraintsを定義しておくことで、データ型がちゃんと定義どおりか、制約も問題ないか(使用するDB・DWHで強制できるもの限定)、をdbt run/build実行時に確認できるようになります。
試してみた
検証環境
- DWH:Snowflake
- dbt Cloud
- dbt-Core:ver1.5 ※Environmentより設定
検証内容
ある中間モデルintermediate_customers.sqlについて、出力されるテーブルのデータ型を保証するために、Contractsを定義してみます。
intermediate_customers.sql
select
customer_id,
first_name,
last_name,
first_order,
number_of_orders
from
{{ ref("int_customer_order_history_joined") }}
これを一度実行しSnowflake上で確認すると、下図のようにデータ型が定義されていました。
Contractsの定義
上述のintermediate_customers.sqlに対してyamlファイルintermediate_customers.ymlを作成し、以下のように定義します。
ポイントは3つあります。
contract:では、enforced: trueとすることで、後述のdata_typeとconstraintsを満たしているか確認するようになるdata_type:では、使用しているDB・DWHのデータ型の名称を用いて、どのデータ型であることを満たさないといけないか、定義するconstraintsでは、使用しているDB・DWHの制約を用いて、どの制約を満たさないといけないか、定義する- ※注意事項:DWHの仕様上で強制できないものは強制できないため別途dbtのテスト機能を用いて保証する必要があります(例えば、Snowflakeでは
not null以外は強制できない)。ただ、constraintsで定義された制約はDDL文に含まれるようになります。
- ※注意事項:DWHの仕様上で強制できないものは強制できないため別途dbtのテスト機能を用いて保証する必要があります(例えば、Snowflakeでは
models:
- name: intermediate_customers
config:
contract:
enforced: true
columns:
- name: customer_id
data_type: varchar
constraints:
- type: not_null
- type: primary_key
tests:
- unique
- not_null
- name: first_name
data_type: varchar
- name: last_name
data_type: varchar
- name: first_order
data_type: date
- name: number_of_orders
data_type: number
constraintsを定義したことによる効果の確認
上述の内容でContractsを定義した上で、一度buildしてみます。
すると、build実行時に「SnowflakeではPrimary Keyは強制していないよ!」とWARNINGが表示されました。Snowflakeにおいてはconstraintsは強制できるnot null制約についてのみ、実際のデータを確認するようです。
実際にSnowflakeで作られたDDL文を見ると、constraintsで定義したprimary keyとnot nullがどちらもDDL文に含まれていることがわかります。Contractsでconstraintsを定義すれば、dbt_constraintsパッケージをインストールしなくても制約をdbtから適用できるので便利ですね!
あえてデータ型をContractsで定義したdata_typeと違うものにしてみる
続いて、data_typeがちゃんと機能しているのかを検証するため、あえてdata_typeと異なるデータ型を出力するようにモデルの定義を変更してみます。
具体的には、customer_idはdata_type: varcharとしてますが、あえてCASTしてintとして出力されるようにしてみます。
select
customer_id::int as customer_id,
first_name,
last_name,
first_order,
number_of_orders
from
{{ ref("int_customer_order_history_joined") }}
この状態でbuildすると、下図のようにThis model has an enforced contract that failed.
Please ensure the name, data_type, and number of columns in your contract match the columns in your model's definition.というエラーメッセージと、具体的にどのカラムにどういった問題があるのかをまとめた表が返ってきます。
このように事前にcontractsを定義しておくことで、data_typeが定義どおりでない場合はエラーを出力してくれることがわかりました!
最後に
dbt-coreのver1.5の新機能「contracts」を試してみました。
あるモデルから出力されるテーブルにおいてデータ型や制約を保証して、後続のモデルやBIツールなどに影響が出ないようにしたい、そんなときに使える機能だと思います!












