😺

Dataformで、BigQueryのデータのテストをする

2023/05/22に公開

初めまして、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上でのテーブルの依存関係は、こんな感じで表現されます。

dataform1

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に直接クエリを投げた場合、以下のような結果が返ってくるように設計しましょう。
dataform2

事前定義されたassertionだけでなく、assertionを自作することで、柔軟なテストを行うことができます。

テストの結果の確認方法

Dataformのテストの結果方法は、2つあります。

1. Dataformの画面上からログ確認

Dataformの画面上から、実行ログを確認することができ、成功 or 失敗も一目でわかります。

Dataformを定期実行する場合、Cloud Loggingで失敗ログを拾い、Slackなどに通知する仕組みを作ると幸せになれそうです。

dataform3

2. テスト結果が保存されるBigQueryを確認

Dataformのテスト結果は、BigQueryにdataform_assertionsというデータセットが作られ、ビューとして保存されます。

dataform4

結果を確認するためには、わざわざビューにクエリを投げる必要があるため、少々面倒ですが、どのデータが違反したかを確認することができます。

dataform5

最後に

Dataformは、あくまでもデータモデリングツールであり、テスト機能はサブ的なものです。
そのため、Dataflowなど他のETLサービスでデータを加工し、テストのためだけにDataformを導入するような使い方はおすすめできません。

BigQueryのテストがしづらいと感じているならば、ETLではなく、BigQueryとDataformを使用したELTに移行することで、テストのしづらさ問題は解消できるのではないでしょうか。

データエンジニアリングのトレンド的にも、ETLよりELTが推されているため、Dataformも機能が追加されて便利になるのではと思っています。

参考

Validate tables with assertions

Discussion