Dataformで、BigQueryのデータのテストをする
初めまして、Data/ML ディビジョンのオーディンです。
本記事では、Dataformで、BigQueryのデータをテストする方法を紹介します。
はじめに
データの品質を保証するために、BigQueryのデータが想定通りかテストしたい場面は多いですが、下記のような理由で、テストが導入しにくい状況でした。
- テスト用のフレームワークがないため、assert句などを使い自分でテスト用のSQLを組む必要があった
- 公式のエミュレータがないため、テストを行うには本物のBigQueryにクエリする必要があり、クエリの実行時間・費用を考慮すると、CIに組み込んでテストを頻繁に実行するのが現実的ではなかった
このテストしづらい問題を、Dataformを使用することで解決することができます。
そこで、この記事では、Dataformの概要とテストの実行方法について解説します。
Dataformとは
Dataformは、SQLXというSQLの拡張言語でデータ変換を行い、依存関係を考慮したBigQueryテーブルを作成してくれるマネージドなデータモデリングツールです。
Dataformは、ELT(Extract、Load、Transform)のTのみを担当するツールで、依存関係があるSQLが多数存在する状況で使うと美味しいサービスです。
よく比較されるサービスとしては、dbtがあります。
マネージドなdbt環境であるdbt cloudが有料なのに対して、Dataformは無料である点が嬉しいですよね。
また、SQLXは、SQLライクな言語なので、SQLを知っている人であれば低い学習コストでDataformを使えるようになると思います。
SQLXの文法
Dataformは、SQLXというSQLの拡張言語で記述します。
SQLXは、configブロックにテーブルの設定を記述し、その下にSQLでテーブルの定義を記述します。
以下は、SQLXの例です。
config {
type: "table",
columns: {
fruit: "name of fruit",
count: "number of fruits sold"
},
assertions: {
nonNull: ["fruit"]
}
}
SELECT
fruit,
count
FROM ${ref("table1")}
UNION ALL
SELECT
fruit,
count
FROM ${ref("table2")}
configブロックの説明
typeオプションで、テーブル or ビューを定義してます。
columnsオプションで、テーブルに含まれる列の説明をしています。
assertionsオプション(本記事のメイン)で、データのテストを行っています。
このassertionsでは、fruitカラムにnullが無いかチェックしています。
他にも色々なオプションがあります。
SQLの説明
SQLでテーブルの定義をしています。
このSQLでは、UNION ALLで2つのテーブルを結合しています。
重要な箇所は、${ref( )}です。
ref関数でテーブルを参照することで、テーブル間での依存関係が確立されます。
ちなみに、Dataform上でのテーブルの依存関係は、こんな感じで表現されます。
Dataformのテスト
上述したように、Dataformでは、configブロック内のassertionsオプションでテストを行うことができます。
nonNull
指定されたカラムのすべての値がNULLでないことをチェックします。
config {
type: "table",
assertions: {
nonNull: ["user_id", "customer_id", "email"]
}
}
SELECT ...
uniqueKey
指定されたカラムの全ての値がユニークであるかをチェックします。
config {
type: "view",
assertions: {
uniqueKey: ["user_id"]
}
}
SELECT ...
uniqueKeys
指定された複数カラムの全ての値がユニークであるかをチェックします。
また、複数カラムの組み合わせがユニークであるかもチェックすることができます。
この例だと、”user_id”がユニークかどうかと、”signup_date”と”customer_id”の組み合わせがユニークかどうかの2つをチェックしています。
config {
type: "table",
assertions: {
uniqueKeys: [["user_id"], ["signup_date", "customer_id"]]
}
}
SELECT ...
rowConditions
指定したカラムの値が、定義したカスタムロジックに従うかをチェックします。
カスタムロジックは SQL で定義します。
正規表現も使用可能です。
config {
type: "table",
assertions: {
rowConditions: [
'signup_date is null or signup_date > "2022-08-01"',
'email like "%@%.%"'
]
}
}
SELECT ...
assertionを自作することも可能
SQLX ファイルにテストロジックを記述し、assertionを自作することも可能です。
config { type: "assertion" }
SELECT
*
FROM
${ref("table3")}
WHERE
user_id IS NULL
OR signup_date IS NULL
OR customer_id IS NULL
configブロックのtypeをassertionにします。
自作assertionは、0行を返すようにクエリを設計します。
BigQueryに直接クエリを投げた場合、以下のような結果が返ってくるように設計しましょう。
事前定義されたassertionだけでなく、assertionを自作することで、柔軟なテストを行うことができます。
テストの結果の確認方法
Dataformのテストの結果方法は、2つあります。
1. Dataformの画面上からログ確認
Dataformの画面上から、実行ログを確認することができ、成功 or 失敗も一目でわかります。
Dataformを定期実行する場合、Cloud Loggingで失敗ログを拾い、Slackなどに通知する仕組みを作ると幸せになれそうです。
2. テスト結果が保存されるBigQueryを確認
Dataformのテスト結果は、BigQueryにdataform_assertionsというデータセットが作られ、ビューとして保存されます。
結果を確認するためには、わざわざビューにクエリを投げる必要があるため、少々面倒ですが、どのデータが違反したかを確認することができます。
最後に
Dataformは、あくまでもデータモデリングツールであり、テスト機能はサブ的なものです。
そのため、Dataflowなど他のETLサービスでデータを加工し、テストのためだけにDataformを導入するような使い方はおすすめできません。
BigQueryのテストがしづらいと感じているならば、ETLではなく、BigQueryとDataformを使用したELTに移行することで、テストのしづらさ問題は解消できるのではないでしょうか。
データエンジニアリングのトレンド的にも、ETLよりELTが推されているため、Dataformも機能が追加されて便利になるのではと思っています。
Discussion