なぜデータ品質テストを自動化すべきか

データ品質の問題は発生してから気づくより、発生する前に自動で検知する仕組みを構築する方が圧倒的にコストが低くなります。品質テストの自動化は、ソフトウェア開発における単体テストと同じ位置づけです。パイプラインに変更を加えるたびに手動で品質確認するのは現実的ではなく、CI/CDに組み込まれた自動テストが品質の安全網になります。

自動テストのないデータパイプラインは「テストなしでデプロイされるWebサービス」と同じです。問題が本番データに流れ込んでから発覚し、意思決定に使われた後で誤りが発覚するという最悪のシナリオを防ぐためにも、品質管理の体系(D-03)と合わせて自動テストを整備することが必須です。

本記事では、データエンジニアが実際に使うツール3つ、dbt tests, Great Expectations, Sodaをコード例付きで解説し、使い分けの判断基準を示します。

dbt testsの活用

dbt testsはdbtモデルに対してカラム単位の品質チェックを行う最もシンプルな方法です。Generic tests(汎用テスト)とSingular tests(カスタムSQLテスト)の2種類があります。

Generic tests — YAML設定例

# models/schema.yml
models:
  - name: fct_orders
    description: "注文ファクトテーブル"
    columns:
      - name: order_id
        tests:
          - not_null
          - unique
      - name: customer_id
        tests:
          - not_null
          - relationships:
              to: ref('dim_customers')
              field: customer_id
      - name: status
        tests:
          - accepted_values:
              values: ['pending', 'processing', 'completed', 'cancelled']
      - name: amount
        tests:
          - not_null

標準の4テスト(not_nulluniqueaccepted_valuesrelationships)で多くの品質要件をカバーできます。dbt-utilsdbt-expectationsパッケージを追加すると、数値範囲チェック・正規表現マッチ・分布チェックなどの高度なテストも利用できます。

Singular test — カスタムSQLテスト例

-- tests/assert_orders_no_negative_amount.sql
-- レコードが返ればテスト失敗
SELECT
    order_id,
    amount
FROM {{ ref('fct_orders') }}
WHERE amount < 0
   OR amount IS NULL

Singular testは「このSQLが0行を返すこと」を成功条件とするカスタムテストです。複雑なビジネスロジックの品質チェック(「キャンセル済み注文の金額が0であること」「返金額が元注文額を超えないこと」等)をSQLで自由に表現できます。

Great Expectationsの活用

Great Expectations(GE)はPythonベースの高機能データ品質テストフレームワークです。dbt testsがdbtモデル専用なのに対し、GEはPandas・Spark・SQL DBなど幅広いデータソースに対応します。自動生成される「Data Docs」(HTML形式の品質レポート)が特徴的です。

Expectation Suite定義例(Python)

import great_expectations as gx

context = gx.get_context()
suite = context.add_expectation_suite("orders_quality_suite")

suite.add_expectation(
    gx.expectations.ExpectColumnValuesToNotBeNull(column="order_id")
)
suite.add_expectation(
    gx.expectations.ExpectColumnValuesToBeUnique(column="order_id")
)
suite.add_expectation(
    gx.expectations.ExpectColumnValuesToBeBetween(
        column="amount", min_value=0, max_value=10000000
    )
)
suite.add_expectation(
    gx.expectations.ExpectColumnValuesToBeInSet(
        column="status",
        value_set=["pending", "processing", "completed", "cancelled"]
    )
)
context.save_expectation_suite(suite)

GE v1以降はAPIが刷新され、よりPythonネイティブな記述スタイルになりました。Expectation Suiteとして定義したルールをAirflow・Prefect等のオーケストレーターから呼び出し、パイプラインの各ステージで品質チェックを実行できます。

Soda(soda-core)の活用

SodaはYAMLベースのDSL「SodaCL」で品質チェックを定義するOSSツールです。SQLを書かずにビジネス担当者でも読み書きしやすいシンプルな構文が特徴で、BigQuery・Snowflake・Spark等に対応しています。

SodaCL — 品質チェック定義例

# checks.yml
checks for fct_orders:
  - row_count > 0
  - missing_count(order_id) = 0
  - duplicate_count(order_id) = 0
  - min(amount) >= 0
  - freshness(created_at) < 6h
  - schema:
      name: Orders schema check
      fail:
        when wrong column type:
          order_id: integer

soda scan -d bigquery -c config.yml checks.ymlコマンドでスキャンを実行し、結果をSoda Cloud(有料)またはCLI出力で確認できます。freshness(created_at) < 6hのようにデータ鮮度チェックを1行で書ける直感的な構文が開発者に好評です。

ツール使い分けの判断基準

3ツール機能比較

比較軸dbt testsGreat ExpectationsSoda(soda-core)
主な用途dbtモデルのカラム品質データレイク・DF上の品質SQL/Spark横断の品質
設定言語YAML + SQLPythonSodaCL(YAML)
dbtとの統合✅(ネイティブ)△(外部連携)✅(dbt-soda連携あり)
ドキュメント自動生成✅(dbt docs)✅(Data Docs)△(Soda Cloud)
鮮度チェック△(カスタムSQL)✅(freshnessネイティブ)
学習コスト中〜高低〜中
OSS/商用OSSGX Core(OSS)/GX Cloud(商用)soda-core(OSS)/Soda Cloud(商用)

ユースケース別推奨ツール

ユースケース推奨ツール
dbtモデルのカラム品質テスト(主軸)dbt tests
ソースデータ(生データ)の品質チェックGreat Expectations / Soda
シンプルな閾値チェックをYAMLで書きたいSoda(SodaCL)
複雑な品質ルールをPythonで定義したいGreat Expectations
既存dbtプロジェクトへ品質テスト追加dbt tests + Soda(補完)
DWH横断でテストを一元管理したいSoda Cloud(有料)

CI/CDへの組み込み

品質テストを開発フローに組み込み、問題がある変更を本番に流さない仕組みを構築します。

PR作成 / コードプッシュ
       │
       ▼
  GitHub Actions / GitLab CI
       │
       ▼
  dbt build (コンパイル + Staging環境でrun)
       │
       ▼
  dbt test (品質テスト実行)
       │
  ┌────┴─────┐
  │PASS       │FAIL
  ▼           ▼
merge承認  PR却下 + コメント通知
       │
       ▼
  本番環境デプロイ(dbt run)
       │
       ▼
  dbt test + Soda scan(本番品質確認)
       │
  ┌────┴─────┐
  │PASS       │FAIL
  ▼           ▼
  完了      Slackアラート→調査・修正

CI環境でのdbt testはStaging DWHに対して実行することで、本番データを汚さずに品質チェックが可能です。GitHub ActionsのYAMLにdbt build --select state:modified+を追加するだけで、変更されたモデルとその依存モデルのみをビルド・テストする差分テストが実現します。

まとめ

データ品質テストの自動化は「パイプラインにシートベルトをつける」作業です。3ツールを組み合わせて多層防御を構築します。

  • dbt tests: dbtモデルのカラム品質チェックの主軸。YAML+SQLで宣言的に定義
  • Great Expectations: ソースデータや複雑なルール定義にはGEをPythonで活用
  • Soda: 鮮度チェックやシンプルな閾値チェックはSodaCLが最も直感的
  • CI/CDへの組み込みで、品質問題をデプロイ前に自動検知する体制を構築

よくある質問(FAQ)

Q. dbt testsだけで品質テストは十分ですか?

A. dbtモデル内のカラム品質チェックにはdbt testsで十分です。ただし、ソースデータ(DWHに入る前の生データ)の品質やパイプライン横断のテスト、鮮度チェックにはGreat ExpectationsやSodaの併用が効果的です。

Q. データ品質テストはどのタイミングで実行すべきですか?

A. パイプライン実行後(dbt test)・PR作成時のCI・定期スケジュール(日次/時間次)の3タイミングが推奨です。特にCI時のテストは「壊れた変更を本番に流さない」安全網として最も重要です。

Q. テストが多すぎるとパフォーマンスに影響しますか?

A. DWH上でSQLとして実行されるため、テーブルスキャンが増えると計算コストが増加します。重要度に応じたテスト密度の設計が重要です。「全カラムにnot_nullをつける」より「ビジネス上重要なカラムに絞る」アプローチを推奨します。