dbtはYAMLで宣言的にテストを書き、アダプタ(Snowflake/BigQuery/Redshift/Sparkなど)向けのSQLにコンパイルして実行します(公式: https://docs.getdbt.com/)。dbt-expectationsは、その仕組みの上でGreat Expectationsに近い豊富な検証マクロを提供するコミュニティパッケージです。
この記事では、試験で問われやすい「テストの選択・設定・解釈」の観点と、実務ですぐ使えるYAML例・運用パターンを整理します。パッケージの具体APIは変更され得るため、原則としてdbtの安定仕様(テスト、セレクタ、severity、store_failures、contracts等)に基づいて記述します。
dbtのテストは「汎用テスト(schema.ymlで宣言)」と「単体データテスト(任意SQL)」に大別されます。dbt-expectationsは前者(汎用テスト)をGreat Expectations風に拡張し、多数の検証マクロをYAMLで簡潔に呼び出せるようにします。試験では、内蔵テスト(not_null, unique, relationships, accepted_values 等)と拡張テストを状況に応じて選べるか、severityの使い分け、テスト結果の解釈(エラー/警告/失敗行の保存)が問われがちです(公式: Testsの基本概念 https://docs.getdbt.com/docs/build/tests)。
ポイントは「テストはSQLにコンパイルされ、対象のモデル/ソースに対して実行される」こと。つまり、記述は宣言的でも、本質は各アダプタ上での集合演算です。テストの負荷・索引利用・日付フィルタは、SQLとして現実的かという観点で判断します。
| 項目 | dbt内蔵テスト | dbt-expectations | Great Expectations(参照) |
|---|---|---|---|
| 定義方法 | schema.ymlのtestsに簡潔指定 | schema.ymlで拡張マクロを指定 | Python/YAMLでexpectationを記述 |
| 特徴 | 基本的制約に強い | 多様な統計/分布/パターン検証 | 極めて表現力が高い |
| 運用負荷 | 最小 | 小〜中(依存パッケージ) | 中(別ランタイム/オーケストレーション) |
dbtテストのコンパイルと実行の流れ(概念)
packages.yml にdbt-expectationsを追加
packages:
- package: calogica/dbt-expectations
version: ">=0.10.0,<1.0.0" # バージョンは実プロジェクトの互換性に合わせて固定
# 追加後に依存関係を取得
# dbt depsdbt-expectationsでは、null/重複/範囲/パターン/関係整合/分布に関する検証をYAMLで宣言できます。ビルトインで足りない“複合一意制約”や“数値が非負かつ範囲内”“正規表現パターン”“行レベル条件付き検証”が書きやすくなります。
以下はモデルordersに対する例です。試験観点では、testsセクションの書式、severityの指定、whereやrow_condition等のフィルタ指定の有無を素早く読み解けるかが大切です。
| 検証 | 典型用途 | SQLに落ちる概念 |
|---|---|---|
| unique_combination_of_columns | 自然キーの重複検出 | GROUP BY + HAVING COUNT(*)>1 |
| expect_column_values_to_be_between | 閾値チェック | BETWEEN / 比較演算 |
| expect_column_values_to_match_regex | ID/メール等の書式 | REGEXP系演算子 |
モデル→テストマクロ→SQL(簡略)
schema.yml でのテスト記述例(dbt-expectations)
version: 2
models:
- name: orders
description: "受注の正規化済みファクト"
columns:
- name: order_id
tests:
- not_null
- unique
- name: customer_email
tests:
- dbt_expectations.expect_column_values_to_match_regex:
regex: "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}
NicheeLab を読み込み中…
quot; severity: warn - name: order_amount tests: - dbt_expectations.expect_column_values_to_be_between: min_value: 0 strictly: true severity: error tests: - dbt_expectations.unique_combination_of_columns: combination_of_columns: [order_id, line_number] severity: error - dbt_expectations.expect_table_row_count_to_be_between: min_value: 1 row_condition: "order_date >= dateadd(day, -7, current_date)" # アダプタ方言に合わせる severity: warn
dbt testは選択構文で対象を絞れます。タグ付けやモデル名、パス指定などを併用し、ローカルでは軽量に、CIではクリティカルなテストを確実に走らせます(公式: Selection syntax)。severity=warnは失敗してもジョブを失敗扱いにしませんが、結果は記録されます。store_failuresは失敗行を永続テーブルとして残し、原因調査を容易にします(公式: Test configs https://docs.getdbt.com/docs/build/tests#test-configs)。
実務では、P0品質(キー重複、NULL不可、参照整合)はseverity=error、健全性モニタ(分布・傾向・軽微な書式)はseverity=warnに分離し、CIで両方を可視化します。
| 設定/実行 | 効果 | 注意点 |
|---|---|---|
| severity: error | 失敗でジョブ失敗 | P0に限定 |
| severity: warn | 失敗でもジョブ継続 | 可視化は必須 |
| store_failures: true | 失敗行を調査可能 | スキーマの掃除/保持期間を決める |
選択的にテストを回す運用イメージ
dbt_project.yml で失敗行保存・タグ・セレクタを設定
name: your_project
version: 1.0.0
config-version: 2
tests:
+store_failures: true
+severity: error # デフォルト、個別テストで上書き
selectors:
- name: critical_tests
definition:
method: fqn
value: tag:p0
# 実行例
# dbt test -s @critical_testsdbtテストは最終的にアダプタ固有SQLになります。正規表現や日付関数、近似集計の挙動は方言差があります。dbt-expectationsの多くのマクロは方言差を吸収しますが、row_conditionやregexの文字クラスなど、引数に生SQLを渡す部分は自環境の方言に合わせる必要があります。
大規模テーブルでは、パーティションや日付条件を前置し、索引/クラスタリングを活かせるクエリ形状になっているかを確認します。
| プラットフォーム | よくある差分 | 対処 |
|---|---|---|
| Snowflake | 正規表現の方言/大文字小文字 | REGEXP系の仕様準拠で書く、テストで小さく検証 |
| BigQuery | 日付の加減算・型 | DATE/TIMESTAMP関数を明示、SAFE_CASTを検討 |
| Spark/Databricks | 一部関数の挙動差 | SQL ANSIモードや関数のドキュメントを参照 |
負荷軽減のための条件適用イメージ
SELECT ... FROM fact
WHERE event_date >= current_date - 7 -- まず期間を絞る
AND partition_col = '2026-04-01' -- パーティションをヒット条件付き検証(row_condition / where の使い分け例)
models:
- name: fact_sessions
tests:
- dbt_expectations.expect_column_values_to_be_between:
column: session_duration_sec
min_value: 0
row_condition: "event_date >= dateadd(day, -1, current_date)" # 方言に合わせる
- name: dim_user
columns:
- name: email
tests:
- dbt_expectations.expect_column_values_to_match_regex:
regex: "^[^@\s]+@[^@\s]+\.[^@\s]+
NicheeLab を読み込み中…
quot;
where: "is_test_user = false" # 一部マクロではwhereではなくrow_conditionを使用dbtのモデル契約(contracts)は、カラム名・型・null許可などのスキーマをビルド時に強制できます(公式: Contracts https://docs.getdbt.com/docs/build/schemas#enforcing-model-contracts)。テストはデータ内容の健全性、contractsはスキーマ形状の保証と役割が異なります。両者を併用すると、API的な互換性とデータ品質の両輪を担保できます。
試験では「どの要件をcontractsで、どれをテストで担保するか」を問われがちです。型・必須列・命名はcontracts、分布/統計/関係はテスト、と整理すると回答しやすくなります。
| 手段 | 強み | 向いている要件 |
|---|---|---|
| contracts | スキーマを即時強制 | 型/必須列/命名・公開インターフェース |
| 内蔵テスト | 基礎品質の網羅 | NULL/一意/参照整合/受容値 |
| dbt-expectations | 高度な内容検証 | 分布/範囲/書式/複合性 |
contractsとtestsの適用タイミング
dbt run (build)
|-- contracts enforce (スキーマ)
`-- models built
`-- dbt test (内容検証)モデルにcontractsを設定しつつテストも併用
models:
- name: fct_orders
config:
contract: {enforced: true}
columns:
- name: order_id
data_type: integer
constraints:
nullable: false
tests:
- unique
- name: order_amount
data_type: numeric
tests:
- dbt_expectations.expect_column_values_to_be_between:
min_value: 0
strictly: true品質ルールをタグとセレクタに落とし、PRで差分のみ・mainで全量・スケジュールで拡張テストという3段階を回すと、速度と品質が両立します。失敗行保存のスキーマ、保持期間、通知方法(CIアーティファクト/BIダッシュボード)も合意しておきます。
dbt-expectationsの採否は段階的に。まずは内蔵テストでP0を固め、次に重要ドメインへ拡張テストを追加、最後に広範囲へ水平展開すると移行コストが抑えられます。
| 環境 | 推奨コマンド/セレクタ | 目的 |
|---|---|---|
| 開発(ローカル) | dbt test -s model_name+ | 対象限定で素早い検証 |
| PR(CI) | dbt test -s state:modified+ tag:p0 | 差分とP0のみで高速に失敗検知 |
| 本番スケジュール | dbt test -s tag:p0,tag:monitor | 品質担保と健全性モニタ |
段階的なテスト実行ストラテジ
selectors.yml の例(CI向け)
selectors:
- name: pr_critical
definition:
union:
- method: state
value: modified+
- method: tag
value: p0
- name: daily_quality
definition:
union:
- method: tag
value: p0
- method: tag
value: monitor
# 実行例
# dbt test -s @pr_critical
# dbt test -s @daily_qualityAnalytics Engineer
問題 1
売上ファクトモデルで、(order_id, line_number)の複合一意性をエラーとして厳格に担保しつつ、amountが0以上であるかは警告として監視したい。SQLを自作せずYAMLで簡潔に記述する最適なアプローチはどれか?
正解: A
要件はYAMLで宣言的に表現でき、複合一意はdbt-expectationsの代表的マクロで対応可能。内容の重要度差はseverityで表現できる。SQL自作や別ツール導入は今回の要件には過剰。
dbt-expectationsは公式機能ですか?試験で必須ですか?
コミュニティパッケージです。試験は公式のテスト概念(汎用/単体、severity、セレクタ等)理解が中心で、特定パッケージAPI暗記は前提ではありません。ただし、拡張テストを使う判断軸は有用です(公式: https://docs.getdbt.com/、認定: https://www.getdbt.com/certifications/analytics-engineer-certification-exam)。
大規模テーブルでテストが重いときの実践策は?
期間や対象を絞るrow_condition/whereの活用、クラスタリング/パーティションキーを先頭でフィルタ、頻度を下げたmonitorタグに分離、失敗行保存で原因を局所化、差分セレクタ(state:modified+)で開発・CIの負荷を抑える、などが現実的です。
contractsとテストはどちらを優先すべきですか?
役割が異なります。スキーマ互換性(型・必須列)はcontractsで即時強制、データ内容の品質(一意・分布・範囲・書式・外部キー整合)はテストで継続検証、という二段構えが推奨です。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
dbt Model の基礎: SQL で定義する変換の最小単位
Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...
dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点
dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...
dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点
dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...
dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト
Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....
dbt_project.yml の読み方:主要設定と命名を最短で掴む
dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...