はじめに
こんにちは、中村です。
皆さんはdbt(data build tool)を使ってデータ変換や管理を行う中で、dbt test
の機能に少し物足りなさを感じたことはありませんか?
dbtはシンプルかつ強力なデータ変換ツールとして非常に便利ですが、標準のdbt test
コマンドで実施できるテストには限界があります。
そこで今回は、dbtの標準機能を補完し、より高度なテストを可能にする拡張パッケージの活用方法について紹介します。
目次
【前提】dbt testでできるテスト
まずは、そもそもdbt testって何ができたのかを確認しましょう!
dbt testにはsingular testとgeneric testの2種類があり、singular testは結果が0件になることを期待するSQLを書き、あってほしくない結果がないか検証するテストです。
例えば、注文日に今日より未来の日付が入っていたら問題ですよね。そのような場合には以下のSQLでテストができます。
#tests/*.sql
SELECT *
FROM {{ ref('orders') }}
WHERE order_date > CURRENT_DATE
一方、generic testにはデフォルトで以下の4種類のテストがあります。
not_null
: nullが含まれていないかunique
: 値が全てuniqueかaccepted_values
:指定した値以外が入っていないかrelationships
: あるカラムに元テーブルのカラムに存在しない値が入っていないか
またcustom generic testがあり、こちらもSQLを記述してテストを作成できます。
こちらはsingular testと異なり、使いまわせるのが利点です。例えば、注文日に限らず日付のカラムで未来の日付が入ってほしくないときは、以下のSQLでテストができます。
#macros/*.sql
{% test assert_not_in_future(model, column_name) %}
SELECT *
FROM {{ model }}
WHERE {{ column_name }} > CURRENT_DATE
{% endtest %}
しかし大量のモデルがあり、それぞれに課したい制約が異なるとき、デフォルトのgeneric testではテスト項目が足りず、singular testやcustom generic testでは記述に手間がかかるという問題があります。そこでdbt_expectationsの出番です。
dbt_expectationsとは
dbt_expectationsは、dbt(data build tool)の拡張パッケージであり、PythonのGreat Expectationsパッケージに着想を得て作られました。検証項目の分類は7種類あり、テスト項目は全部で62項目もあります。(dbt testと被る項目があります。)
テスト項目の分類
- テーブルの形状 (Table shape)
列や行の数、構成、最近のデータ存在確認など、テーブルの外形的品質チェックを行う検証項目群- expect_column_to_exist
指定したカラムが存在することを検証
- expect_row_values_to_have_recent_data
指定したカラムに、最新の日付(または時刻)データが含まれているかをチェック - expect_grouped_row_values_to_have_recent_data
グループ単位(例:customer_idごと)で最新のデータがあるかを検証 - expect_table_aggregation_to_equal_other_table
集計値(sum, count など)が別のテーブルと一致するかを確認 - expect_table_column_count_to_be_between
カラム数が指定された範囲内であるかをチェック - expect_table_column_count_to_equal_other_table
カラム数が別テーブルと一致していることを確認 - expect_table_columns_count_to_equal
正確なカラム数であることを検証する
- expect_table_columns_to_not_contain_set
指定したカラムがテーブルに含まれていないことを確認 - expect_table_columns_to_contain_set
指定したカラムがすべて存在することを確認 - expect_table_columns_to_match_ordered_list
指定された順序でカラムが並んでいることを検証 - expect_table_columns_to_match_set
指定したカラムの集合と完全一致していることを確認(順序は問わない) - expect_table_row_count_to_be_between
テーブルの行数が指定された範囲内にあることを検証する - expect_table_row_count_to_equal_other_table
別テーブルと行数が一致しているかを確認 - expect_table_row_count_to_equal_other_table_times_factor
別テーブルの行数に係数を掛けた数と一致するかをチェック - expect_table_row_count_to_equal
正確に指定した件数であることを確認
- expect_column_to_exist
- 欠損値、一意な値、およびデータ型 (Missing values, unique values, and types)
カラムの欠損・一意性・型の整合性を検証するための検証項目群- expect_column_values_to_be_null
カラムの値がNULLであることを検証 - expect_column_values_to_not_be_null
カラムにNULLが含まれていないことを確認 - expect_column_values_to_be_unique
各カラムの値が一意であることを検証
- expect_column_values_to_be_of_type
カラムが指定されたデータ型であることを検証 - expect_column_values_to_be_in_type_list
指定された複数の型のいずれかに該当するかを検証 - expect_column_values_to_have_consistent_casing
文字列カラムの大文字小文字の一貫性をチェック
- expect_column_values_to_be_null
- セットと範囲 (Sets and ranges)
値の集合・範囲・傾向(増減)に関する検証項目群- expect_column_values_to_be_in_set
各カラムの値が指定されたセット内にあることを検証 - expect_column_values_to_not_be_in_set
カラムの値が指定した値の集合に含まれていないことを検証
- expect_column_values_to_be_between
各カラムの値が2つの値の間にあることを検証 - expect_column_values_to_be_decreasing
カラムの値が降順になっているかを確認 - expect_column_values_to_be_increasing
カラムの値が昇順になっているかを確認
- expect_column_values_to_be_in_set
- 文字列マッチング (String matching)
長さ・パターンマッチ(LIKE / 正規表現)を通して、データの形式的な整合性を確認する検証項目群- expect_column_value_lengths_to_be_between
文字列の長さが指定された範囲内にあることを確認 - expect_column_value_lengths_to_equal
文字列の長さが指定した長さと正確に一致することを確認 - expect_column_values_to_match_like_pattern
SQL の LIKE パターン(例:abc%
)に一致することを確認 - expect_column_values_to_match_like_pattern_list
複数のLIKEパターンのいずれかに一致することを確認 - expect_column_values_to_match_regex
1つの正規表現パターンに一致することを確認 - expect_column_values_to_match_regex_list
複数の正規表現パターンのいずれかに一致することを確認 - expect_column_values_to_not_match_like_pattern
指定したLIKEパターンに一致しないことを検証する - expect_column_values_to_not_match_like_pattern_list
指定された複数の LIKE パターンに一致しないことを確認 - expect_column_values_to_not_match_regex
指定した正規表現に一致しないことを検証 - expect_column_values_to_not_match_regex_list
複数の正規表現パターンのいずれにも一致しないことを確認
- expect_column_value_lengths_to_be_between
- 集計関数 (Aggregate functions)
列単位の集計結果を基にデータ品質を検証する検証項目群- expect_column_distinct_count_to_be_greater_than
ユニークな値の数が指定した値より大きいことを検証 - expect_column_distinct_count_to_be_less_than
ユニークな値の数が指定した値より小さいことを検証 - expect_column_distinct_count_to_equal_other_table
他のテーブルの同じ列とユニーク値数が等しいことを検証 - expect_column_distinct_count_to_equal
ユニーク値数がぴったり指定値と等しいことを検証 - expect_column_distinct_values_to_be_in_set
ユニークな値のすべてが指定セットに含まれているかを検証 - expect_column_distinct_values_to_contain_set
指定した値のセットが列のユニーク値の中にすべて含まれていることを検証 - expect_column_distinct_values_to_equal_set
ユニーク値が指定セットと完全に一致することを検証 - expect_column_max_to_be_between
列の最大値が指定された範囲内にあるかを検証 - expect_column_mean_to_be_between
列の平均値が指定された範囲にあるかを検証 - expect_column_median_to_be_between
列の中央値が範囲内かを検証 - expect_column_min_to_be_between
列の最小値が指定された範囲にあるかを検証 - expect_column_most_common_value_to_be_in_set
最頻値(mode)が指定された集合の中にあるかを検証 - expect_column_proportion_of_unique_values_to_be_between
ユニーク値の割合(ユニーク数 ÷ 総行数)が指定された範囲内かを検証 - expect_column_quantile_values_to_be_between
任意の分位点の値が範囲内かを検証 - expect_column_stdev_to_be_between
標準偏差が範囲内かを検証 - expect_column_sum_to_be_between
列の合計値が範囲内かを検証 - expect_column_unique_value_count_to_be_between
ユニーク値の数が指定した範囲にあるかを検証(distinct_count と同義)
- expect_column_distinct_count_to_be_greater_than
- 複数カラム (Multi-column)
複数列を同時に評価し整合性を検証する検証項目群- expect_column_pair_values_A_to_be_greater_than_B
列 A の値が列 B より常に大きいことを検証 - expect_column_pair_values_to_be_equal
2列の値が同じであることを検証 - expect_column_pair_values_to_be_in_set
2列のペア(タプル)が指定された組み合わせセットに含まれているかを検証 - expect_compound_columns_to_be_unique
指定した複数列の組み合わせが一意(ユニーク)であることを検証 - expect_multicolumn_sum_to_equal
指定した複数列の合計値が別の列と一致することを検証 - expect_select_column_values_to_be_unique_within_record
1レコード内で指定列群の値がすべて異なることを検証
- expect_column_pair_values_A_to_be_greater_than_B
- 分布関数 (Distributional functions)
標準偏差や時系列パターンに基づき、データの異常値や欠損パターンをチェックするための検証項目群- expect_column_values_to_be_within_n_moving_stdevs
移動平均と移動標準偏差に基づいて、列の値が過去の傾向(N標準偏差以内)に収まっているかを検証 - expect_column_values_to_be_within_n_stdevs
カラムの値が平均からn標準偏差以内であることを検証 - expect_row_values_to_have_data_for_every_n_datepart
指定の「期間単位(datepart)」で欠損なくデータがあるかを検証。例:毎日、毎週、毎月に少なくとも1件のデータがあるかを検証
- expect_column_values_to_be_within_n_moving_stdevs
dbt_expectationsを使ってみた
事前準備
まずpackages.ymlに以下を追加
packages:
- package: metaplane/dbt_expectations
version: 0.10.8 # バージョンは適宜変更してください
次にdbt depsを実行してください
dbt deps
最後にdbt_project.ymlでタイムゾーンを設定
vars:
dbt_date_time_zone: 'Asia/Tokyo'
実行
今回は架空の製造業の製造ログデータを用いて検証項目を実際に使っていきます。
製品のマスターと製造ログをJOINしつつ、データの品質チェックをします。
今回使用するdbt-expectationsの検証項目は以下の3つです。これらをデフォルトのgeneric testと組み合わせて使ってみます。
- expect_column_pair_values_A_to_be_greater_than_B
- dbt_expectations.expect_column_sum_to_be_between
- expect_column_values_to_match_regex
#ファイル構成
dbt_project/
├── models/
│ ├── staging/
│ │ ├── stg_production_logs.sql
│ │ ├── stg_production_logs.yml
│ │ ├── stg_product_master.sql
│ │ ├── stg_product_master.yml
│ ├── marts/
│ │ ├── production_logs.sql
├── seeds/
│ ├── seed_production_logs.csv
│ ├── seed_product_master.csv
各ファイルの中身は以下の通りです。
stg_product_master.sql
SELECT *
FROM {{ ref('seed_product_master') }}
stg_product_master.yml
version: 2
models:
- name: stg_product_master
description: "プロダクトマスターのステージングテーブル"
columns:
- name: product_id
description: "製品ID(主キー)"
tests:
- not_null
- unique
- dbt_expectations.expect_column_values_to_match_regex:
regex: '^P[0-9]{3}$'
- name: product_name
description: "製品名"
tests:
- not_null
stg_production_logs.sql
SELECT *
FROM {{ ref('seed_production_logs') }}
stg_production_logs.yml
version: 2
models:
- name: stg_production_logs
description: "製造業のログテーブル"
tests:
- dbt_expectations.expect_column_pair_values_A_to_be_greater_than_B:
column_A: end_time
column_B: start_time
or_equal: True
columns:
- name: log_id
description: "ログの一意な識別子"
tests:
- not_null
- unique
- dbt_expectations.expect_column_values_to_match_regex:
regex: '^[0-9]{4}$'
- name: line_id
description: "生産ライン識別子"
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: '^LINE_[A-D]$'
- name: product_id
description: "製品識別子"
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: '^P[0-9]{3}$'
- name: operator_id
description: "オペレーター識別子"
tests:
- not_null
- dbt_expectations.expect_column_values_to_match_regex:
regex: '^OP[0-9]{2}$'
- name: temperature
description: "処理時の温度(度)"
tests:
- not_null
- dbt_expectations.expect_column_sum_to_be_between:
min_value: 60
max_value: 100
- name: start_time
description: "処理開始日時"
tests:
- not_null
- name: end_time
description: "処理終了日時"
tests:
- not_null
- name: status
description: "処理状態(OK, FAILなど)"
tests:
- not_null
- accepted_values:
values: ['OK', 'FAIL']
- name: part1_qty
description: "部品1の個数"
- name: part2_qty
description: "部品2の個数"
- name: total_parts
description: "部品合計個数"
production_logs.sql
SELECT *
FROM {{ ref('stg_production_logs') }}
LEFT JOIN {{ ref('stg_product_master') }}
USING(product_id)
seeds/seed_product_master.csv
product_id,product_name
P001,Product_1
P002,Product_2
P003,Product_3
P004,Product_4
P005,Product_5
P006,Product_6
P007,Product_7
P008,Product_8
P009,Product_9
P010,Product_10
seeds/seed_production_logs.csv
log_id,line_id,product_id,operator_id,temperature,start_time,end_time,status,part1_qty,part2_qty,total_parts
1001,LINE_B,P003,OP01,77.48,2024-04-02 14:24:00,2024-04-02 14:35:00,OK,3,2,5
1002,LINE_A,P004,OP02,74.31,2024-04-08 01:14:00,2024-04-08 01:51:00,OK,1,1,2
1003,LINE_B,P008,OP05,78.24,2024-04-07 17:15:00,2024-04-07 17:37:00,FAIL,5,4,9
1004,LINE_C,P005,OP02,82.62,2024-04-01 09:46:00,2024-04-01 10:44:00,OK,2,4,6
1005,LINE_A,P006,OP03,73.83,2024-04-05 03:54:00,2024-04-05 04:10:00,FAIL,1,4,5
1006,LINE_A,P007,OP01,73.83,2024-04-01 19:51:00,2024-04-01 20:47:00,FAIL,4,5,9
1007,LINE_A,P004,OP03,82.9,2024-04-05 10:45:00,2024-04-05 11:31:00,OK,2,1,3
1008,LINE_D,P006,OP02,78.84,2024-04-03 23:34:00,2024-04-03 23:50:00,FAIL,4,3,7
1009,LINE_B,P009,OP02,72.65,2024-04-05 09:00:00,2024-04-05 09:23:00,OK,3,1,4
1010,LINE_B,P006,OP01,77.71,2024-04-06 14:13:00,2024-04-06 14:47:00,OK,3,5,8
1011,LINE_A,P004,OP05,72.68,2024-04-01 16:45:00,2024-04-01 17:15:00,FAIL,4,3,7
1012,LINE_D,P003,OP03,72.67,2024-04-03 18:03:00,2024-04-03 18:54:00,OK,4,4,8
1013,LINE_C,P010,OP04,76.21,2024-04-04 03:20:00,2024-04-04 04:17:00,FAIL,5,5,10
1014,LINE_D,P002,OP01,65.43,2024-04-05 10:50:00,2024-04-05 11:14:00,OK,2,5,7
1015,LINE_A,P007,OP04,66.38,2024-04-03 01:44:00,2024-04-03 02:34:00,FAIL,2,4,6
1016,LINE_A,P009,OP03,72.19,2024-04-07 08:29:00,2024-04-07 08:55:00,FAIL,5,1,6
1017,LINE_D,P001,OP03,69.94,2024-04-02 14:27:00,2024-04-02 14:55:00,OK,4,2,6
1018,LINE_B,P003,OP03,76.57,2024-04-07 02:37:00,2024-04-07 02:53:00,OK,3,5,8
1019,LINE_C,P008,OP01,70.46,2024-04-07 11:17:00,2024-04-07 12:16:00,OK,5,1,6
1020,LINE_B,P010,OP01,67.94,2024-04-05 11:07:00,2024-04-05 11:36:00,OK,2,1,3
1021,LINE_B,P008,OP05,82.33,2024-04-06 20:42:00,2024-04-06 20:56:00,OK,5,2,7
1022,LINE_B,P009,OP02,73.87,2024-04-04 08:22:00,2024-04-04 09:05:00,FAIL,5,4,9
1023,LINE_D,P002,OP02,75.34,2024-04-05 20:57:00,2024-04-05 21:49:00,OK,3,4,7
1024,LINE_B,P010,OP02,67.88,2024-04-02 01:29:00,2024-04-02 02:00:00,OK,1,5,6
1025,LINE_A,P001,OP03,72.28,2024-04-02 03:23:00,2024-04-02 04:18:00,OK,1,2,3
1026,LINE_B,P009,OP02,75.55,2024-04-07 04:23:00,2024-04-07 04:48:00,FAIL,3,4,7
1027,LINE_B,P002,OP01,69.25,2024-04-04 02:21:00,2024-04-04 03:21:00,FAIL,4,4,8
1028,LINE_A,P002,OP01,76.88,2024-04-05 08:44:00,2024-04-05 09:21:00,FAIL,4,4,8
1029,LINE_B,P009,OP04,72.0,2024-04-05 04:39:00,2024-04-05 04:55:00,OK,2,2,4
1030,LINE_B,P002,OP04,73.54,2024-04-06 03:12:00,2024-04-06 03:33:00,OK,3,4,7
1031,LINE_A,P004,OP02,71.99,2024-04-01 21:48:00,2024-04-01 22:39:00,FAIL,5,1,6
1032,LINE_A,P003,OP04,84.26,2024-04-06 20:36:00,2024-04-06 21:16:00,OK,2,4,6
1033,LINE_D,P009,OP04,74.93,2024-04-05 18:36:00,2024-04-05 19:02:00,OK,4,3,7
1034,LINE_A,P006,OP01,69.71,2024-04-03 11:51:00,2024-04-03 12:19:00,OK,2,1,3
1035,LINE_B,P001,OP05,79.11,2024-04-07 23:31:00,2024-04-08 00:11:00,OK,5,5,10
1036,LINE_B,P007,OP01,68.9,2024-04-03 10:44:00,2024-04-03 10:58:00,OK,5,1,6
1037,LINE_A,P007,OP05,76.04,2024-04-07 22:05:00,2024-04-07 22:53:00,FAIL,1,5,6
1038,LINE_C,P007,OP02,65.2,2024-04-04 07:12:00,2024-04-04 07:35:00,FAIL,3,2,5
1039,LINE_D,P010,OP05,68.36,2024-04-06 12:51:00,2024-04-06 13:21:00,OK,1,1,2
1040,LINE_C,P003,OP03,75.98,2024-04-02 04:00:00,2024-04-02 04:44:00,OK,2,5,7
1041,LINE_D,P009,OP03,78.69,2024-04-04 02:42:00,2024-04-04 03:15:00,OK,3,2,5
1042,LINE_C,P002,OP01,75.86,2024-04-07 15:26:00,2024-04-07 15:55:00,OK,1,2,3
1043,LINE_C,P004,OP03,74.42,2024-04-04 10:22:00,2024-04-04 10:50:00,FAIL,5,2,7
1044,LINE_C,P001,OP01,73.49,2024-04-04 04:34:00,2024-04-04 04:47:00,FAIL,1,4,5
1045,LINE_D,P009,OP04,67.61,2024-04-02 19:43:00,2024-04-02 20:33:00,OK,3,2,5
1046,LINE_A,P006,OP05,71.4,2024-04-02 14:32:00,2024-04-02 14:46:00,OK,2,5,7
1047,LINE_C,P001,OP03,72.7,2024-04-06 05:21:00,2024-04-06 05:39:00,OK,1,3,4
1048,LINE_D,P010,OP02,80.29,2024-04-04 04:08:00,2024-04-04 05:00:00,OK,1,3,4
1049,LINE_B,P006,OP04,76.72,2024-04-03 04:22:00,2024-04-03 04:43:00,OK,4,1,5
1050,LINE_A,P008,OP02,66.18,2024-04-04 08:51:00,2024-04-04 09:11:00,OK,1,4,5
1051,LINE_B,P001,OP02,76.62,2024-04-06 13:41:00,2024-04-06 14:13:00,FAIL,3,2,5
1052,LINE_C,P009,OP04,73.07,2024-04-05 01:38:00,2024-04-05 02:05:00,FAIL,1,3,4
1053,LINE_C,P001,OP01,71.62,2024-04-01 15:32:00,2024-04-01 15:49:00,FAIL,3,2,5
1054,LINE_A,P007,OP05,78.06,2024-04-05 06:23:00,2024-04-05 07:19:00,OK,3,4,7
1055,LINE_B,P006,OP04,80.15,2024-04-04 05:33:00,2024-04-04 05:45:00,OK,4,1,5
1056,LINE_C,P009,OP03,79.66,2024-04-05 02:09:00,2024-04-05 02:58:00,FAIL,3,1,4
1057,LINE_B,P004,OP04,70.8,2024-04-05 01:04:00,2024-04-05 01:39:00,FAIL,3,5,8
1058,LINE_D,P009,OP01,73.45,2024-04-03 07:31:00,2024-04-03 08:20:00,FAIL,5,3,8
1059,LINE_C,P008,OP04,76.66,2024-04-04 14:20:00,2024-04-04 14:43:00,FAIL,4,5,9
1060,LINE_A,P005,OP05,79.88,2024-04-03 18:21:00,2024-04-03 19:03:00,FAIL,4,2,6
1061,LINE_B,P004,OP02,72.6,2024-04-02 09:30:00,2024-04-02 10:28:00,OK,2,3,5
1062,LINE_A,P008,OP04,74.07,2024-04-01 20:37:00,2024-04-01 21:02:00,OK,4,5,9
1063,LINE_B,P001,OP01,69.47,2024-04-05 16:51:00,2024-04-05 17:32:00,FAIL,4,2,6
1064,LINE_A,P009,OP02,69.02,2024-04-03 19:45:00,2024-04-03 20:06:00,OK,5,4,9
1065,LINE_C,P008,OP05,79.06,2024-04-06 12:38:00,2024-04-06 12:56:00,FAIL,4,5,9
1066,LINE_D,P005,OP02,81.78,2024-04-07 13:36:00,2024-04-07 14:14:00,FAIL,2,4,6
1067,LINE_D,P002,OP03,74.64,2024-04-07 06:20:00,2024-04-07 07:01:00,OK,2,3,5
1068,LINE_A,P003,OP02,80.02,2024-04-04 10:11:00,2024-04-04 10:42:00,OK,3,5,8
1069,LINE_A,P007,OP04,76.81,2024-04-05 16:35:00,2024-04-05 17:29:00,FAIL,2,2,4
1070,LINE_B,P007,OP04,71.77,2024-04-07 12:10:00,2024-04-07 12:49:00,OK,4,1,5
1071,LINE_C,P005,OP04,76.81,2024-04-07 21:12:00,2024-04-07 21:46:00,FAIL,4,1,5
1072,LINE_B,P008,OP02,82.69,2024-04-07 10:58:00,2024-04-07 11:55:00,FAIL,5,5,10
1073,LINE_C,P007,OP02,74.82,2024-04-06 07:00:00,2024-04-06 07:41:00,FAIL,1,4,5
1074,LINE_D,P010,OP05,82.82,2024-04-02 18:51:00,2024-04-02 19:40:00,OK,5,1,6
1075,LINE_D,P003,OP01,61.9,2024-04-02 06:55:00,2024-04-02 07:46:00,FAIL,4,2,6
1076,LINE_C,P006,OP04,79.11,2024-04-05 15:31:00,2024-04-05 16:01:00,FAIL,2,4,6
1077,LINE_A,P009,OP01,75.44,2024-04-06 03:06:00,2024-04-06 03:32:00,FAIL,1,4,5
1078,LINE_A,P004,OP02,73.5,2024-04-03 21:13:00,2024-04-03 22:04:00,OK,1,1,2
1079,LINE_A,P010,OP02,75.46,2024-04-03 01:36:00,2024-04-03 02:01:00,FAIL,2,4,6
1080,LINE_A,P003,OP03,65.06,2024-04-04 05:58:00,2024-04-04 06:57:00,OK,3,2,5
1081,LINE_D,P007,OP02,73.9,2024-04-07 22:01:00,2024-04-07 22:12:00,OK,3,5,8
1082,LINE_C,P010,OP01,76.79,2024-04-08 01:40:00,2024-04-08 02:34:00,OK,2,1,3
1083,LINE_A,P009,OP03,82.39,2024-04-05 06:48:00,2024-04-05 07:32:00,OK,4,3,7
1084,LINE_C,P008,OP02,72.41,2024-04-06 02:42:00,2024-04-06 03:23:00,FAIL,1,4,5
1085,LINE_D,P008,OP04,70.96,2024-04-03 08:05:00,2024-04-03 09:01:00,FAIL,5,3,8
1086,LINE_D,P004,OP04,72.49,2024-04-05 00:00:00,2024-04-05 00:25:00,FAIL,1,3,4
1087,LINE_B,P008,OP02,79.58,2024-04-05 03:51:00,2024-04-05 04:02:00,FAIL,4,3,7
1088,LINE_C,P009,OP01,76.64,2024-04-04 06:32:00,2024-04-04 07:03:00,OK,3,5,8
1089,LINE_B,P008,OP04,72.35,2024-04-02 07:22:00,2024-04-02 07:47:00,FAIL,4,4,8
1090,LINE_D,P004,OP03,77.57,2024-04-01 12:42:00,2024-04-01 12:57:00,FAIL,3,2,5
1091,LINE_D,P009,OP03,75.49,2024-04-06 17:13:00,2024-04-06 17:58:00,FAIL,5,3,8
1092,LINE_B,P002,OP02,79.84,2024-04-06 11:54:00,2024-04-06 12:21:00,FAIL,3,3,6
1093,LINE_B,P004,OP04,71.49,2024-04-02 16:38:00,2024-04-02 17:35:00,FAIL,5,2,7
1094,LINE_C,P002,OP02,73.36,2024-04-08 00:59:00,2024-04-08 01:57:00,FAIL,5,5,10
1095,LINE_A,P009,OP02,73.04,2024-04-03 22:07:00,2024-04-03 22:40:00,FAIL,2,3,5
1096,LINE_B,P008,OP01,67.68,2024-04-01 20:25:00,2024-04-01 20:38:00,OK,5,3,8
1097,LINE_D,P006,OP02,76.48,2024-04-07 20:45:00,2024-04-07 21:13:00,OK,4,4,8
1098,LINE_D,P008,OP01,76.31,2024-04-04 04:56:00,2024-04-04 05:36:00,OK,1,1,2
1099,LINE_A,P004,OP01,75.03,2024-04-03 01:25:00,2024-04-03 01:44:00,FAIL,5,3,8
1100,LINE_D,P008,OP04,73.83,2024-04-08 05:33:00,2024-04-08 06:21:00,FAIL,5,2,7
1101,LINE_A,P010,OP01,67.92,2024-04-08 00:42:00,2024-04-08 01:19:00,OK,3,5,8
1102,LINE_B,P003,OP05,72.9,2024-04-03 17:37:00,2024-04-03 18:03:00,OK,1,2,3
1103,LINE_D,P005,OP01,73.29,2024-04-03 02:44:00,2024-04-03 02:54:00,OK,4,4,8
1104,LINE_A,P004,OP03,70.99,2024-04-04 14:40:00,2024-04-04 15:35:00,OK,3,4,7
1105,LINE_B,P005,OP02,74.19,2024-04-06 04:05:00,2024-04-06 04:22:00,OK,5,2,7
1106,LINE_C,P008,OP01,77.02,2024-04-02 00:17:00,2024-04-02 00:37:00,FAIL,3,5,8
1107,LINE_D,P008,OP01,84.43,2024-04-04 19:02:00,2024-04-04 19:56:00,OK,4,3,7
1108,LINE_C,P001,OP01,75.87,2024-04-06 05:58:00,2024-04-06 06:55:00,OK,3,5,8
1109,LINE_A,P003,OP04,76.29,2024-04-07 21:04:00,2024-04-07 21:51:00,FAIL,1,3,4
1110,LINE_D,P002,OP04,74.63,2024-04-04 11:57:00,2024-04-04 12:18:00,FAIL,5,4,9
1111,LINE_B,P006,OP04,65.41,2024-04-05 23:30:00,2024-04-06 00:01:00,FAIL,3,1,4
1112,LINE_A,P008,OP01,74.87,2024-04-04 14:42:00,2024-04-04 15:34:00,FAIL,4,5,9
1113,LINE_A,P009,OP04,75.3,2024-04-04 04:55:00,2024-04-04 05:25:00,FAIL,1,4,5
1114,LINE_D,P008,OP01,87.32,2024-04-01 22:48:00,2024-04-01 23:10:00,OK,5,3,8
1115,LINE_D,P008,OP01,74.04,2024-04-04 08:55:00,2024-04-04 09:40:00,OK,2,3,5
1116,LINE_A,P009,OP04,76.51,2024-04-08 06:15:00,2024-04-08 06:40:00,OK,2,3,5
1117,LINE_B,P008,OP03,74.83,2024-04-03 21:21:00,2024-04-03 21:38:00,FAIL,4,1,5
1118,LINE_D,P009,OP02,69.16,2024-04-06 01:27:00,2024-04-06 02:07:00,FAIL,4,2,6
1119,LINE_A,P005,OP04,80.71,2024-04-03 12:02:00,2024-04-03 12:50:00,FAIL,5,2,7
1120,LINE_C,P010,OP05,78.76,2024-04-07 02:38:00,2024-04-07 03:05:00,FAIL,1,3,4
1121,LINE_C,P006,OP05,78.96,2024-04-03 00:34:00,2024-04-03 01:12:00,FAIL,5,4,9
1122,LINE_D,P004,OP04,70.45,2024-04-06 12:20:00,2024-04-06 12:50:00,OK,2,2,4
1123,LINE_D,P003,OP04,82.01,2024-04-04 22:53:00,2024-04-04 23:50:00,OK,4,4,8
1124,LINE_A,P008,OP01,67.99,2024-04-02 18:28:00,2024-04-02 19:10:00,FAIL,5,3,8
1125,LINE_B,P002,OP04,77.93,2024-04-01 12:11:00,2024-04-01 13:07:00,FAIL,2,4,6
1126,LINE_C,P009,OP04,85.95,2024-04-05 04:26:00,2024-04-05 05:15:00,FAIL,4,1,5
1127,LINE_A,P004,OP03,70.05,2024-04-06 21:14:00,2024-04-06 21:58:00,OK,1,5,6
1128,LINE_D,P003,OP03,72.17,2024-04-02 08:40:00,2024-04-02 09:17:00,OK,1,1,2
1129,LINE_C,P006,OP04,75.5,2024-04-01 20:33:00,2024-04-01 21:03:00,OK,1,3,4
1130,LINE_B,P003,OP02,72.48,2024-04-04 02:40:00,2024-04-04 03:23:00,OK,4,5,9
1131,LINE_D,P010,OP02,67.25,2024-04-08 06:25:00,2024-04-08 06:59:00,OK,5,2,7
1132,LINE_C,P001,OP04,75.34,2024-04-06 13:55:00,2024-04-06 14:45:00,FAIL,3,4,7
1133,LINE_C,P010,OP03,69.69,2024-04-07 13:15:00,2024-04-07 13:35:00,FAIL,1,4,5
1134,LINE_D,P008,OP01,77.37,2024-04-04 04:17:00,2024-04-04 04:56:00,OK,3,2,5
1135,LINE_C,P005,OP01,70.4,2024-04-05 16:08:00,2024-04-05 16:54:00,FAIL,3,5,8
1136,LINE_D,P005,OP02,82.75,2024-04-04 10:57:00,2024-04-04 11:07:00,FAIL,5,1,6
1137,LINE_C,P003,OP01,71.08,2024-04-03 19:48:00,2024-04-03 20:38:00,OK,2,5,7
1138,LINE_C,P003,OP01,73.39,2024-04-04 20:21:00,2024-04-04 21:21:00,FAIL,4,1,5
1139,LINE_B,P003,OP05,79.07,2024-04-05 01:12:00,2024-04-05 02:09:00,FAIL,4,2,6
1140,LINE_C,P008,OP03,68.85,2024-04-07 08:57:00,2024-04-07 09:39:00,FAIL,3,2,5
1141,LINE_B,P007,OP05,76.14,2024-04-02 15:26:00,2024-04-02 16:05:00,FAIL,1,2,3
1142,LINE_C,P009,OP01,81.54,2024-04-02 08:39:00,2024-04-02 09:39:00,FAIL,4,1,5
1143,LINE_D,P006,OP01,66.96,2024-04-05 12:38:00,2024-04-05 13:31:00,OK,3,5,8
1144,LINE_C,P010,OP02,75.92,2024-04-06 16:44:00,2024-04-06 16:55:00,OK,5,5,10
1145,LINE_A,P003,OP01,76.3,2024-04-06 14:46:00,2024-04-06 15:40:00,OK,3,4,7
1146,LINE_B,P009,OP02,78.91,2024-04-04 19:06:00,2024-04-04 19:47:00,FAIL,1,1,2
1147,LINE_B,P007,OP01,68.82,2024-04-06 11:52:00,2024-04-06 12:25:00,FAIL,5,4,9
1148,LINE_B,P008,OP04,68.4,2024-04-05 23:26:00,2024-04-05 23:53:00,OK,1,3,4
1149,LINE_C,P001,OP04,77.61,2024-04-05 11:02:00,2024-04-05 11:18:00,FAIL,3,5,8
1150,LINE_B,P010,OP01,76.48,2024-04-03 11:49:00,2024-04-03 12:06:00,OK,4,1,5
1151,LINE_B,P002,OP05,76.25,2024-04-05 03:04:00,2024-04-05 03:29:00,OK,2,5,7
1152,LINE_B,P010,OP01,76.73,2024-04-08 00:07:00,2024-04-08 00:30:00,FAIL,2,3,5
1153,LINE_B,P002,OP01,71.6,2024-04-02 23:30:00,2024-04-02 23:48:00,OK,5,3,8
1154,LINE_C,P001,OP02,76.16,2024-04-01 12:03:00,2024-04-01 12:35:00,FAIL,2,5,7
1155,LINE_A,P002,OP04,76.47,2024-04-01 22:18:00,2024-04-01 22:36:00,FAIL,4,5,9
1156,LINE_D,P009,OP02,71.43,2024-04-05 10:51:00,2024-04-05 11:33:00,OK,5,1,6
1157,LINE_A,P008,OP04,84.33,2024-04-07 06:23:00,2024-04-07 06:52:00,FAIL,4,1,5
1158,LINE_A,P006,OP05,77.37,2024-04-02 13:28:00,2024-04-02 14:09:00,OK,4,1,5
1159,LINE_C,P007,OP05,69.04,2024-04-02 01:56:00,2024-04-02 02:14:00,FAIL,3,5,8
1160,LINE_A,P002,OP05,78.28,2024-04-06 11:53:00,2024-04-06 12:35:00,OK,5,4,9
1161,LINE_C,P008,OP04,70.13,2024-04-06 05:26:00,2024-04-06 06:04:00,FAIL,2,4,6
1162,LINE_C,P006,OP02,78.94,2024-04-02 09:57:00,2024-04-02 10:27:00,FAIL,4,3,7
1163,LINE_D,P002,OP03,80.79,2024-04-02 02:19:00,2024-04-02 02:34:00,OK,1,1,2
1164,LINE_C,P002,OP04,70.9,2024-04-07 15:55:00,2024-04-07 16:08:00,FAIL,5,5,10
1165,LINE_C,P006,OP01,79.82,2024-04-06 03:29:00,2024-04-06 04:25:00,OK,1,3,4
1166,LINE_A,P006,OP05,77.06,2024-04-03 02:15:00,2024-04-03 03:07:00,FAIL,4,2,6
1167,LINE_B,P007,OP05,79.11,2024-04-02 15:22:00,2024-04-02 16:20:00,OK,3,5,8
1168,LINE_B,P005,OP03,84.48,2024-04-08 06:17:00,2024-04-08 07:09:00,FAIL,3,1,4
1169,LINE_D,P002,OP02,73.77,2024-04-05 07:51:00,2024-04-05 08:01:00,OK,2,2,4
1170,LINE_D,P007,OP04,71.23,2024-04-02 09:03:00,2024-04-02 10:00:00,FAIL,5,2,7
1171,LINE_A,P001,OP02,70.55,2024-04-03 02:58:00,2024-04-03 03:31:00,OK,3,3,6
1172,LINE_D,P007,OP04,70.92,2024-04-01 21:35:00,2024-04-01 22:28:00,FAIL,1,3,4
1173,LINE_A,P006,OP04,74.61,2024-04-06 01:05:00,2024-04-06 01:32:00,OK,2,5,7
1174,LINE_C,P001,OP02,76.71,2024-04-04 13:20:00,2024-04-04 14:13:00,FAIL,5,4,9
1175,LINE_C,P004,OP02,76.38,2024-04-08 03:39:00,2024-04-08 03:52:00,FAIL,1,2,3
1176,LINE_D,P007,OP02,79.14,2024-04-04 15:02:00,2024-04-04 15:32:00,OK,1,1,2
1177,LINE_C,P002,OP04,75.07,2024-04-05 15:49:00,2024-04-05 16:33:00,OK,2,5,7
1178,LINE_C,P010,OP04,82.27,2024-04-06 07:07:00,2024-04-06 07:18:00,FAIL,4,1,5
1179,LINE_A,P006,OP02,73.68,2024-04-06 02:03:00,2024-04-06 02:31:00,FAIL,1,4,5
1180,LINE_B,P007,OP05,88.6,2024-04-05 10:48:00,2024-04-05 11:03:00,FAIL,4,1,5
1181,LINE_C,P004,OP03,78.13,2024-04-07 07:04:00,2024-04-07 07:19:00,OK,4,3,7
1182,LINE_B,P006,OP03,70.71,2024-04-02 04:51:00,2024-04-02 05:33:00,OK,1,5,6
1183,LINE_B,P003,OP05,69.65,2024-04-04 00:31:00,2024-04-04 00:47:00,OK,2,3,5
1184,LINE_D,P010,OP05,77.41,2024-04-02 04:34:00,2024-04-02 04:55:00,FAIL,4,4,8
1185,LINE_D,P008,OP03,73.88,2024-04-04 22:19:00,2024-04-04 22:38:00,FAIL,4,1,5
1186,LINE_A,P005,OP04,78.57,2024-04-08 01:29:00,2024-04-08 01:42:00,FAIL,3,5,8
1187,LINE_A,P002,OP05,77.37,2024-04-01 18:16:00,2024-04-01 18:29:00,FAIL,3,3,6
1188,LINE_D,P010,OP02,74.64,2024-04-06 14:21:00,2024-04-06 15:08:00,FAIL,5,1,6
1189,LINE_A,P008,OP01,70.77,2024-04-08 05:12:00,2024-04-08 05:52:00,FAIL,5,2,7
1190,LINE_B,P008,OP04,67.43,2024-04-02 07:01:00,2024-04-02 07:43:00,OK,2,1,3
1191,LINE_D,P006,OP05,72.77,2024-04-05 11:22:00,2024-04-05 11:55:00,OK,3,4,7
1192,LINE_D,P005,OP03,79.28,2024-04-05 03:22:00,2024-04-05 03:36:00,OK,3,1,4
1193,LINE_C,P005,OP04,76.07,2024-04-05 03:01:00,2024-04-05 03:16:00,OK,5,2,7
1194,LINE_D,P006,OP02,68.77,2024-04-08 02:29:00,2024-04-08 03:24:00,OK,1,3,4
1195,LINE_C,P005,OP02,75.87,2024-04-06 03:37:00,2024-04-06 04:19:00,OK,3,1,4
1196,LINE_B,PD03,OP02,76.93,2024-04-05 05:18:00,2024-04-05 06:17:00,OK,4,2,6
1197,LINE_A,P006,OP05,70.58,2024-04-04 16:46:00,2024-04-04 17:46:00,GOOD,1,5,6
1198,LINE_B,P010,OP02,275.77,2024-04-08 03:05:00,2024-04-08 03:39:00,FAIL,2,2,4
1199,LINE_K,P010,OP03,75.29,2024-04-01 19:55:00,2024-04-01 20:31:00,FAIL,3,2,5
1200,LINE_D,P004,OP03,69.29,2024-04-04 00:37:00,2024-04-03 23:53:00,FAIL,2,3,5
今回はseeds/seed_production_logs.csvの最後5行が検証項目に引っかかるようにしています。
- 196行目→product_idがPD03でPと3桁の数字に当てはまらない
- 197行目→statusがOKでもFAILでもない
- 198行目→tempurtureが275.77度で明らかに高い
- 199行目→line_idがLINE_KでLINE_AからLINE_Dまでに当てはまらない
- 200行目→start_timeとend_timeが逆になっている
1196,LINE_B,PD03,OP02,76.93,2024-04-05 05:18:00,2024-04-05 06:17:00,OK,4,2,6
1197,LINE_A,P006,OP05,70.58,2024-04-04 16:46:00,2024-04-04 17:46:00,GOOD,1,5,6
1198,LINE_B,P010,OP02,375.77,2024-04-08 03:05:00,2024-04-08 03:39:00,FAIL,2,2,4
1199,LINE_K,P010,OP03,75.29,2024-04-01 19:55:00,2024-04-01 20:31:00,FAIL,3,2,5
1200,LINE_D,P004,OP03,69.29,2024-04-04 00:37:00,2024-04-03 23:53:00,FAIL,2,3,5
それでは実行していきましょう。プロジェクトのあるディレクトリでdbt buildを実行
dbt build
実行すると以下のような返答がかえってくると思います。

想定通りに5個の検証項目でfailになっていますね。成功です。
まとめ
今回はdbt-expectationsを使って、dbt testでは手間のかかる検証ををやってみました。個人的にはIDを正規表現でテストできるのはありがたいと思いました。扱うデータによって使える検証項目は様々だと思います。ぜひ実際にご自身で気になる検証項目を試してみてください!
またdbtについて興味のある方は、ぜひこちらのブログもご覧ください!