DuckDBでdbt
TL;DR
DuckDBとdbtでモデリングのサンプル作成して検証しました。
主な目的はPandasとdbtモデリングのそれぞれで使い分けるべき場面を見極めたい。
得意分野
まず、dbtとPandasの得意分野を比較。
モジュール化&再利用性など運用効率を考慮した時に差が出そうです。
Aspect | dbt の特徴 | Pandas の特徴 |
---|---|---|
スケーラビリティ | SQL を用いてデータウェアハウス上で直接処理するため、大規模データの変換・処理が可能。 | メモリ内で処理するため、大規模データの場合にパフォーマンスやメモリ制約が発生。 |
モジュール化 & 再利用性 | SQL モデルとして変換ロジックを分割し、依存関係を明示的に管理できる。Jinja テンプレートを利用したコードの再利用性も高い。 | スクリプトベースで記述するため、コードの分割や依存関係管理は手動で行う必要があり、保守性は低め。 |
テスト & ドキュメント生成 | 組み込みのテスト機能(not_null 、unique など)があり、また dbt docs generate でモデル間の依存関係(DAG)を自動生成できる。 |
テストフレームワークやドキュメント生成機能は標準で備わっておらず、別途実装が必要。 |
バージョン管理 & チーム開発 | SQL/YAML ファイルとして管理されるため、Git などのバージョン管理ツールや CI/CD パイプラインとの連携が容易。 | Python スクリプトとして管理されるが、データパイプライン全体の変更管理や依存関係の把握はやや困難。 |
プロダクション運用 | バッチ処理や自動テスト、エラーハンドリングなど、プロダクション向けのデータ変換パイプラインの構築に適している。 | 主にデータ探索やアドホックな分析に向いており、プロダクション運用を想定した機能は限定的。 |
BIツール連動 | そもそもDBを保持しているので連動は容易。 | 連動するためには別途DBなどを容易する必要がある。 |
dbtのメリット
SQLコードのバージョン管理と共有:
SQLでデータ変換ロジックを記述するため、Gitなどのバージョン管理システムを通じて、コードの変更履歴やコラボレーションが容易になります。
モデル間の依存関係の自動管理:
各SQLモデル(変換ロジック)の依存関係を明示的に定義でき、dbtが自動で依存関係グラフを生成・管理します。これにより、パイプライン全体の流れを把握しやすくなります。
データ品質テストの自動化:
組み込みのテスト機能(not_null、unique、カスタムテストなど)を利用して、変換後のデータ品質を自動的に検証し、問題を早期に発見できます。
自動ドキュメント生成:
dbtは、モデルの依存関係や変換ロジックをもとに、ドキュメントとデータラインエージを自動生成します。これにより、チーム全体でデータパイプラインの理解が深まります。
再利用性と一貫性の向上:
Jinjaテンプレートやマクロを用いることで、共通のロジックやコードを再利用でき、変換ルールの一貫性を保ちながら開発効率を向上させます。
CI/CDパイプラインとの統合:
dbtは、Gitと連携してCI/CD環境での自動テスト・デプロイが可能なため、変更があった際の迅速な反映や品質管理が実現できます。
スケーラブルなデータパイプラインの構築:
データウェアハウス上で直接変換を実行するため、大規模データに対しても高いパフォーマンスで処理を行うことができます。
透明性と監査性の向上:
すべての変換ロジックがコードとして管理されるため、誰がいつどのような変更を加えたかを追跡しやすく、監査対応も容易です。
データカタログ:
自動生成されたドキュメントは、データカタログとして利用でき、利用者がデータの内容や変換ロジック、品質基準を容易に参照できる環境を提供します。
dbtの操作方法
Seed
$ dbt seed
07:56:16 Running with dbt=1.9.2
07:56:16 Registered adapter: duckdb=1.9.1
07:56:16 Found 5 models, 4 seeds, 426 macros
07:56:16
07:56:16 Concurrency: 1 threads (target='dev')
07:56:16
07:56:16 1 of 4 START seed file main.customers .......................................... [RUN]
07:56:17 1 of 4 OK loaded seed file main.customers ...................................... [INSERT 3 in 0.05s]
07:56:17 2 of 4 START seed file main.dates .............................................. [RUN]
07:56:17 2 of 4 OK loaded seed file main.dates .......................................... [INSERT 3 in 0.02s]
07:56:17 3 of 4 START seed file main.products ........................................... [RUN]
07:56:17 3 of 4 OK loaded seed file main.products ....................................... [INSERT 3 in 0.02s]
07:56:17 4 of 4 START seed file main.sales .............................................. [RUN]
07:56:17 4 of 4 OK loaded seed file main.sales .......................................... [INSERT 3 in 0.02s]
07:56:17
07:56:17 Finished running 4 seeds in 0 hours 0 minutes and 0.27 seconds (0.27s).
07:56:17
07:56:17 Completed successfully
07:56:17
07:56:17 Done. PASS=4 WARN=0 ERROR=0 SKIP=0 TOTAL=4
Run
$ dbt run
07:57:14 Running with dbt=1.9.2
07:57:15 Registered adapter: duckdb=1.9.1
07:57:15 Found 5 models, 4 seeds, 426 macros
07:57:15
07:57:15 Concurrency: 1 threads (target='dev')
07:57:15
07:57:15 1 of 5 START sql view model main.dim_customers ................................. [RUN]
07:57:15 1 of 5 OK created sql view model main.dim_customers ............................ [OK in 0.06s]
07:57:15 2 of 5 START sql view model main.dim_dates ..................................... [RUN]
07:57:15 2 of 5 OK created sql view model main.dim_dates ................................ [OK in 0.03s]
07:57:15 3 of 5 START sql view model main.dim_products .................................. [RUN]
07:57:15 3 of 5 OK created sql view model main.dim_products ............................. [OK in 0.14s]
07:57:15 4 of 5 START sql view model main.fact_sales .................................... [RUN]
07:57:15 4 of 5 OK created sql view model main.fact_sales ............................... [OK in 0.03s]
07:57:15 5 of 5 START sql view model main.star_schema_view .............................. [RUN]
07:57:15 5 of 5 OK created sql view model main.star_schema_view ......................... [OK in 0.03s]
07:57:15
07:57:15 Finished running 5 view models in 0 hours 0 minutes and 0.48 seconds (0.48s).
07:57:15
07:57:15 Completed successfully
07:57:15
07:57:15 Done. PASS=5 WARN=0 ERROR=0 SKIP=0 TOTAL=5
DBデータ確認
import duckdb
import pandas as pd
# DuckDB データベースファイルに接続
con = duckdb.connect('duckdb.db')
# star_schema_view テーブルの先頭 10 行を DataFrame として取得
df = con.execute('SELECT * FROM star_schema_view LIMIT 10').df()
# DataFrame を表示
df
Document
以下コマンドでドキュメント作成できます。モデル間の関係性を確認する事が可能です。
$ dbt docs generate
Modeling
Modelingはスターを採用、各モデルの依存関係がより明確になり再利用性が高まります。
以下のように定義しています。
- dim(ディメンション): 製品、顧客、日付など、背景となる説明的な情報を保持するテーブル。
- fact(ファクト): 売上や取引など、実際の事象の数値データやメトリクスを保持するテーブル。
- star(スタースキーマ): 中心にファクトテーブルを持ち、その周囲に複数のディメンションテーブルを配置するデータモデリング手法。これにより、データの集計や分析が容易になります。
Dim(ディメンションテーブル)
意味・役割
ディメンションテーブルは、ファクトテーブルで記録される数値的な事象(測定値)の背景にある「属性情報」や「説明情報」を保持します。
具体的には、顧客、製品、日付、地域などの情報がこれにあたります。
特徴
背景情報の提供
ファクトテーブルの数値データに対して、より詳細な属性情報を付加し、データの意味を理解しやすくします。
説明的な情報を保持
例:顧客の名前や住所、製品のカテゴリーや価格帯、日付に関する詳細情報など。
クエリでのフィルタリングに利用
レポート作成時や分析時に、特定の属性(例:特定の地域、特定の期間)でデータを絞り込むための条件として利用されます。
例
- dim_customers
- 顧客ID、顧客名、住所、地域など
- dim_products
- 製品ID、製品名、カテゴリー、価格帯など
- dim_dates
- 日付、年、月、四半期など
Fact(ファクトテーブル)
意味・役割
ファクトテーブルは、実際の事象や取引の数値データ(測定値)を記録するテーブルです。
売上や数量、利益、コストなどの集計値を保持し、ビジネスのパフォーマンスを評価するための基礎データとなります。
特徴
数値的な測定値を格納
売上金額、数量、利益などの数値データが中心となります。
外部キーの活用
各レコードは、ディメンションテーブルのキー(例:顧客ID、製品ID、日付キー)を参照することで、背景情報と紐づけられています。
集計や分析の中心
ビジネス分析やレポート作成時に、主にこのファクトテーブルが利用され、さまざまな指標の集計や統計解析が行われます。
例
- fact_sales
- 各売上取引において、どの顧客がどの製品を、どの日にどれだけ購入したか(数量、金額など)を記録
Star(スタースキーマ)
意味・役割
スタースキーマは、データモデリングの設計パターンの一つで、中心にファクトテーブルを配置し、その周囲に複数のディメンションテーブルを配置することで「星形(スター)」のような構造を実現します。
特徴
シンプルな構造。ファクトテーブルを中心とし、ディメンションテーブルが放射状に配置されるため、全体像が直感的に把握しやすい。
パフォーマンスの向上
JOIN の数が比較的少なく、クエリがシンプルになるため、分析処理が高速に行えます。
使いやすい分析環境
データのスライス&ダイス(切り口ごとの集計や分析)が容易になり、BI ツールとの連携もスムーズです。
repo
参考
Discussion