はじめに
以前、Fivetranについて調べた際に、
Fivetran
↓
データを取得・連携
Snowflake
↓
データを保存・処理
dbt
↓
データを加工
という役割分担があることを知りました。
そこで気になったのが、
「dbtって結局何をするツールなの?」
「SQLでデータを加工するなら、普通にSQLを実行するだけではダメなの?」
「modelsフォルダにSQLを置くのはなぜ?」
という点です。
今回は、データ基盤でよく利用される**dbt(data build tool)**について、初心者向けに整理してみます。
dbtとは?
dbtは一言でいうと、
「SQLによるデータ変換処理を、ソフトウェア開発のように管理・実行するためのツール」
です。
例えば、Snowflakeに以下のような注文データが格納されているとします。
orders
customer_id | product_id | amount
------------|------------|-------
1 | 100 | 3000
1 | 200 | 2000
2 | 100 | 5000
ここから、
「顧客ごとの購入金額を集計したテーブルを作りたい」
となった場合、SQLなら、
SELECT
customer_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
のように加工できます。
dbtでも、基本的にはこのようなSELECT文を使ってデータ変換処理を記述します。
では、
「普通にSQLを実行するのと何が違うの?」
という疑問が出てきます。
ここがdbtを理解するうえで重要なポイントです。
dbtではSQLを「モデル」として管理する
dbtでは、データを変換するSQLを**Model(モデル)**という単位で管理します。
例えば、
models/
├── staging/
│ └── stg_orders.sql
│
└── marts/
└── customer_sales.sql
のように、modelsフォルダ配下へSQLファイルを配置します。
例えば、
models/marts/customer_sales.sql
に、
SELECT
customer_id,
SUM(amount) AS total_amount
FROM ...
GROUP BY customer_id
と記述します。
そしてdbtを実行すると、このSQLをもとにデータウェアハウス上へテーブルやViewなどを作成できます。
つまり、
SQLファイル
↓
dbt
↓
SnowflakeへSQLを実行
↓
Table / Viewなどを作成
という流れになります。
dbt自身がデータを加工しているわけではない
ここは最初に勘違いしやすいポイントでした。
例えば、
dbt
↓
Snowflake
という構成の場合、実際に大量のデータを処理するのは基本的にSnowflake側です。
dbtは、
SQLモデルを読み込む
↓
SQLを組み立てる
↓
SnowflakeへSQLを送る
↓
SnowflakeがSQLを実行
という役割を担当します。
そのため、dbtはSnowflakeなどのデータウェアハウスの計算能力を利用してデータを変換します。
ref()でモデル同士をつなげられる
dbtの特徴の一つがモデル間の依存関係を管理できることです。
例えば、
生データ
↓
stg_orders
↓
customer_sales
という順番でデータを加工するとします。
customer_sales.sqlからstg_ordersを利用したい場合、
SELECT
customer_id,
SUM(amount) AS total_amount
FROM {{ ref('stg_orders') }}
GROUP BY customer_id
のように記述できます。
この、
{{ ref('stg_orders') }}
がdbtの重要な機能です。
ref()を利用すると、dbtがモデル同士の依存関係を認識できます。
つまり、
stg_orders
↓
customer_sales
という関係をdbt側で把握できます。
モデルが増えて、
raw_orders
↓
stg_orders
↓
daily_sales
↓
monthly_sales
のようになっても、モデル同士の依存関係を管理しやすくなります。
source()とは?
dbtでは、dbtが作成したモデルだけでなく、もともとデータウェアハウスに存在するデータも利用します。
そのような外部のデータを参照する際に利用されるのが、
source()
です。
例えば、
SELECT *
FROM {{ source('sales', 'orders') }}
のように記述できます。
イメージすると、
Fivetranなど
↓
Snowflake
↓
RAW.orders
│
│ source()
▼
stg_orders
│
│ ref()
▼
customer_sales
となります。
source()はdbtの外から入ってきた元データ、ref()はdbtのモデル同士をつなぐもの、と考えると理解しやすいです。
dbtを実行する
dbtではコマンドを利用してモデルを実行できます。
代表的なのが、
dbt run
です。
これを実行すると、対象となるdbtモデルが実行されます。
例えば、
models/
├── stg_orders.sql
├── stg_customers.sql
└── customer_sales.sql
があれば、dbtがモデル間の依存関係を考慮して処理します。
また、
dbt test
によってデータテストを実行したり、
dbt build
によってモデルの構築やテストなどをまとめて実行したりできます。
dbtにはこのように、単にSQLを実行するだけではなく、データ変換処理を開発・検証するための仕組みが用意されています。(dbt Developer Hub)
dbtではデータのテストもできる
個人的にdbtを調べていて、
「SQLを管理するだけじゃないんだ」
と思ったのがテスト機能です。
例えば、
customer_idにはNULLが入ってはいけない
という条件があるとします。
dbtでは、このようなデータ品質に関するテストを定義できます。
代表的なチェックとしては、
NULLではないか
値が一意になっているか
想定した値だけが入っているか
別テーブルに対応する値が存在するか
などがあります。
そして、
dbt test
を実行することでチェックできます。
データ加工処理とテストを同じプロジェクト内で管理できるのは、普通にSQLファイルをバラバラに管理する場合との大きな違いです。
dbtならGitで管理できる
dbtではSQLモデルなどをファイルとして管理するため、Gitを使ったバージョン管理とも相性が良いです。
例えば、
main
│
├── feature/add-sales-model
│
▼
SQLを修正
↓
commit
↓
push
↓
Pull Request
↓
レビュー
↓
merge
という、アプリケーション開発でよく見る流れをデータ変換処理にも取り入れられます。
これが、
「SQLによるデータ加工をソフトウェア開発のように扱う」
というdbtの特徴につながっています。
dbt Coreとは?
dbtについて調べると、
dbt Core
という名前もよく出てきます。
dbt Coreは、コマンドラインから利用できるdbtの実行環境です。
例えば、自分のPCやDockerコンテナなどにdbt Coreをインストールして、
dbt run
などを実行できます。
そのため、
ECS / Fargate
↓
Docker Container
↓
dbt Core
↓
Snowflake
のように、AWS ECS上のコンテナからdbtを実行する構成も考えられます。
この場合もECSがデータ加工を行うのではなく、
ECS
↓
dbtを実行
dbt
↓
SQLをSnowflakeへ送信
Snowflake
↓
実際のデータ処理
という役割分担になります。
Snowflakeとの関係
dbtとSnowflakeも競合するものではありません。
役割を分けると、
Snowflake
→ データを保存・処理する
dbt
→ Snowflake上で「どのようにデータを変換するか」をSQLモデルとして管理する
という関係です。
例えば、
Snowflake
RAW
│
│ dbt
▼
STAGING
│
│ dbt
▼
MART
のように、Snowflakeに取り込まれた生データを段階的に加工していく際にdbtを利用できます。
Fivetranとの違い
Fivetranとdbtの違いも整理しておきます。
Fivetranは主に、
外部システム → データウェアハウス
のデータ連携を担当します。
一方dbtは、
データウェアハウス内のデータ → 加工済みデータ
というTransformを担当します。
例えば、
Salesforce
NetSuite
PostgreSQL
│
▼
Fivetran
│
│ Extract / Load
▼
Snowflake
│
▼
dbt
│ Transform
▼
分析用データ
という構成です。
そのため、
Fivetran = 運ぶ
Snowflake = 貯める・処理する
dbt = 加工方法を管理する
と覚えると分かりやすいと思います。
普通のSQLとdbtは何が違う?
ここまで調べて、
「結局SQLを書くなら、直接SQLを実行すればいいのでは?」
という最初の疑問に戻ります。
例えばSQLファイルを個別に実行するだけの場合、
01_staging.sql
02_sales.sql
03_customer.sql
04_monthly.sql
と増えていくと、
「どのSQLを先に実行する?」
「このSQLはどのテーブルに依存している?」
「修正によってデータがおかしくなっていない?」
「このテーブルは何のために作った?」
といった管理が難しくなってきます。
dbtを利用すると、
SQLによるデータ変換
+
モデル間の依存関係
+
テスト
+
ドキュメント
+
Gitによるコード管理
という形で、データ変換処理をプロジェクトとして管理できます。
つまりdbtの価値は、
「SQLを書けること」ではなく、「増えていくSQLによるデータ変換処理を管理しやすくすること」
にあると理解しました。
今回調べて分かったこと
調べる前は、
「dbtってSQLを実行するためのツールなのかな?」
くらいの認識でした。
しかし実際には、単にSQLを実行するだけではなく、
models
↓
SQLによるデータ変換
ref / source
↓
依存関係の管理
test
↓
データ品質チェック
Git
↓
バージョン管理
といった仕組みを利用して、データ変換処理そのものを開発・管理しやすくするツールだと分かりました。
特に、
Fivetran
↓
Snowflake
↓
dbt
という流れで考えると、dbtがデータ基盤のどの部分を担当するのか理解しやすかったです。
まとめ
今回はdbtについて調べてみました。
ポイントをまとめると、
- dbtはSQLを中心にデータ変換処理を開発・管理するツール
- SQLファイルをModelとして管理する
-
ref()でモデル間の依存関係を表現できる -
source()で元データを参照できる -
dbt runでモデルを実行できる - テストやドキュメント化にも対応している
- Gitを利用した開発フローと相性が良い
- SnowflakeなどのDWH上で実際のデータ処理を行う
- Fivetranなどで取り込んだデータをdbtで加工する構成が考えられる
ということが分かりました。
個人的には、
dbt = SQLによるデータ加工を「ちゃんとした開発」として管理するためのツール
と理解すると、かなりイメージしやすいと思います。
Snowflakeを使ったデータ基盤を学ぶうえでは、SQLだけでなく、dbtがどのようにデータ変換処理を管理しているのかまで理解しておくと、実際のデータパイプラインをイメージしやすくなりそうです。