dbtでのデプロイの検証について
dbtに限らずETLプロセスの修正をデプロイする際には、修正の影響がある指標・属性について以下のような検証を行う必要がある (と思っている)
- 修正前後で集計結果に差異がないか
- 修正前後で集計結果に差異は発生しているが、発生原因は説明がつくものか 1
dbt(v1.8~)で用意されているテストとして以下の2つがあるが、これらのテストだけでは、上記が問題ないことを保証しきることは難しいと思っている
- Data tests : 主にデータの品質確認のために実施する
- Unit tests : 主にモデルのロジックが正しいかを実施する
Recce
を使えば、dbtの修正の検証が容易にでき、かつ検証の自動化まで行えそうなことが分かったため、使用方法やどんな感じのことができるかをまとめたいと思う
Recceについて
以下は公式サイトからの引用
Recce is a data-change validation tool for dbt projects. Recce provides a convenient platform to perform cross-environment diffs as data modeling validations. Use these validations in your pull request (PR) comment to demonstrate proof-of-correctness of your modeling changes and speed up thew QA process of PR review.
Recce
はdbtの異なる環境間を比較検証するためのプラットフォームで、プルリクでRecce
を使うことで、検証のプロセスを加速させることができるよ、というようなことを書いていると思う
使い方
説明の都合上、どのようにすれば使えるかを先に説明する
デモ用のリポジトリを用意しているので、こちらを使えばRecceを手元で確認できると思う
手順
前提として、環境が2つ以上必要となる。以下はDuckDBにつなぐ際のprofiles.ymlの例である 2
jaffle_shop:
target: dev
outputs:
dev:
type: duckdb
path: 'jaffle_shop.duckdb'
schema: main
prod:
type: duckdb
path: 'jaffle_shop.duckdb'
schema: prod
Recce
をインストールする
pip install -U recce
Recce
の機能をフルに使うために、package.ymlに以下の2つのパッケージを追加したうえで、dbt deps
を実行する
packages:
- package: dbt-labs/audit_helper
version: 0.11.0
- package: data-mie/dbt_profiler
version: 0.8.1
Recce
はdbt docsと同様にRecce
サーバーをlocalにホストして、Webブラウザ上で使うことになるが、Recce
サーバーをホストするために以下の2つのアーティファクトが必要となる
- manifest.json
- catalog.json
そのため、これらのアーティファクトを比較元(prod環境)と比較先(dev環境)で用意する必要がある。さらに、アーティファクトの保存先を以下のように環境ごとに分ける必要がある
環境 | アーティファクトの保存ディレクトリ |
---|---|
prod環境 | target-base/ |
dev環境 |
target/ (デフォルトの保存先) |
比較元(prod環境)でのアーティファクト作成は以下のように行う
git switch main # mainブランチがprod環境と同期していると仮定
dbt build -t prod
dbt docs generate -t prod --target-path target-base/
比較先(dev環境)でのアーティファクトの作成は以下のように行う
git switch feature/my-awesome-feature # 修正を行っているブランチに移動する
dbt build
dbt docs generate
最後に、Recce
サーバーを起動する。サーバーへはブラウザからアクセスできる
recce server
Recceの特徴
Recce
は以下のような機能を含んでいる
- WebUIによる修正の検証
- CLIによる修正の検証・検証の自動化
- 検証結果をstateファイルとして保存・共有する
- 定常的に行う比較をpresetとして登録・コード管理し、自動的に検証できるようにする
WebUIによる修正の検証
Webブラウザからは以下の3つのページが確認できる
- Lineage
- Query
- Checks
Lineageページ
Recceで基本となるところ(だと思っている)で、リネージグラフ上で修正があったモデルのみが確認できる。非常に見やすい (修正があったモデル以外も含めて表示することも可能)
リネージグラフ上の各モデルをクリックすると、モデルごとの比較結果が確認できる(画像では、ordersをクリックしている)
デフォルトでは、スキーマの比較画面とカラム数の比較(99 rows
のところ)が見られる。上の</> Diff
、下のAdvanced Diffs
をクリックすることで、そのほかの比較が確認できる
</> Diff
をクリックするとモデルごとのコードのDiffが確認できる。リネージグラフからたどり着いているので、GitHub上で確認するよりもコードの理解度が高くなると思う
Advanced Diffs
からは現状4種類の比較ができる
項目 | 比較内容 | 特に有用なカラム |
---|---|---|
Profile Diff | カラムごとに基礎統計量を比較する | any |
Value Diff | カラムごとにどのくらい値が一致しているかを比較する | any |
Top-K Diff | 選択したカラムについて、取りうる値ごとに値の件数を比較する。占有割合が大きい順にソートされて表示される | カテゴリカラム |
Histogram Diff | 選択したカラムを基にヒストグラムを作成し、比較する | 数値カラム |
実際の画面は以下のようになる
- Profile Diff
- Value Diff
- Top-K Diff
- Histogram Diff
Add check
やAdd to checklist
をクリックすると後述するChecksページに比較結果を追加できる
Queryページ
クエリを修正前後のモデルに対して発行して、クエリ結果を簡単に比較できる。クエリにはJinjaテンプレートを使用できる(ref
以外のマクロも使えると思う)
UIは以下のようになっている
-
Run
ボタンもしくはcommand(ctrl)+Enterでクエリを実行可能。Run diff
で修正前後の両方のモデルに対してクエリを実行し比較できる - 画面右の
Primary key
が修正前後を比較する際のキーになる(なくても比較はできる) - 画面右下の
Changed only
をオンにすれば、差異があったレコードだけに絞れる - クエリ結果右上の
+
から、Checksページに比較結果を追加できる
Checksページ
今までで追加した比較結果ともともとpresetとして設定されていた比較結果を確認できる。
各比較結果にはチェックをつけることが可能
比較結果のコピー・保存
比較結果のコピーと保存は以下のように簡単にできる
- 比較結果を画像としてコピー
- Lineageページでいうと、下画像右端の赤枠で囲ったコピーマークをクリックすると、リネージグラフのコピーができ、プルリクのコメント等にそのまま貼り付けることができる(貼り付けた結果)。ほかの画面でもワンクリックでコピーができる
- 比較結果をstateファイルとして保存
- 画面右上のエクスポートボタンを押すと、Checksで新たに追加した比較結果を含めてstateファイルとして保存ができる。stateファイルについては後述する
CLIによる修正の検証・検証の自動化
CLIコマンドとしては以下の2つが用意されている
コマンド | 処理内容 |
---|---|
recce run |
比較結果をstateファイル(recce-state.json)に出力 |
recce summary |
stateファイルのサマリをmd形式で表示 |
recce summary
コマンドによって生成される結果は、githubのコメント用に最適化されている(表示例)ので、例えば、Github Actions内で、
- recce runでステートファイル作成
- recce summaryでサマリのテキスト作成
- ghコマンド等でサマリのテキストをプルリクのコメントとして追加
とすることで、CI/CDに組み込むことができる
上記を含む内容をすでに公式は用意しているので、詳しい実装に興味がある人は以下リンクを確認してほしい
検証結果をstateファイルとして保存・共有する
WebUIやCLIの説明ですでに登場しているが、比較・検証結果をstateファイルというjsonファイルに保存できる
作成したstateファイル(=recce-state.json
)を元に以下コマンドを使うと、レビューモードでRecce
サーバーを起動できる
recce server --review recce-state.json
stateファイルは以下の情報から構成される
項目 | JSONキー | 内容 |
---|---|---|
Checks | "checks" |
Checksページに表示されている比較の設定 |
Runs | "runs" |
Checksページに表示されている比較の実行結果 |
Environments' Artifacts | "artifacts" |
比較元と比較先のアーティファクト(=manifest.json, catalog.json) |
Runtime Information | "git" |
gitのブランチの情報など |
例えば、プルリクのレビュープロセスにおいて、プルリク作成者がstateファイルを保存し、レビュアーに共有することができる。レビュアーは、レビューモードでReccaサーバーを起動することで、
- 比較の実行結果(=Runs)が保持されているので、レビュアーはクエリを実行することなく比較・検証結果を確認できる
- アーティファクト情報が保持されているので、レビュアーはdbt docs generateなどの追加のコマンドなしに、
Recce
サーバー上で比較クエリを発行することができる
定常的に行う比較をpresetとして登録・コード管理する
dbtプロジェクトのルートディレクトリに以下のような内容を、recce.ymlとして保存することで、Recce
サーバーのChecksページ上にpresetとして登録することができる
また、recce run
コマンドでも、presetとして登録された比較が実行されるので、比較を自動化する際には必須の設定となる
checks:
- name: Query diff of customers
description: |
This is the demo preset check.
Please run the query and paste the screenshot to the PR comment.
type: query_diff
params:
sql_template: select * from {{ ref("customers") }}
view_options:
primary_keys:
- customer_id
changed_only: true
現在は設定項目に関するドキュメントはないので、WebUIからコードを取得するしかない(下画像参照)が、検証の自動化のためには強力なツールとなる
読み方
Recceは「レーキー」と読むらしい(/ˈrɛki/: 'reconnaissance'の略)
注意事項
stateファイルについて
前述したように、stateファイルはクエリの実行結果を含むので、クエリ結果に個人情報が含まれないように気を付ける必要がある。そのため、例えば以下のような対策が必要になってくると思われる
- カラムレベルマスキング等でクエリを行っても個人情報が表示されないようにする
- CI/CDで自動化する際に生成されるstateファイルを定期的に削除する
Snowflakeでの使用について
Snowflakeをよく使うので、Snowflakeで使用するうえでの注意点をまとめておく
Snowflake上で実行する場合のprofiles.yml
は以下のようになると思われる
jaffle_shop:
target: dev
outputs:
dev:
type: snowflake
account: <orgname>-<account_name>
role: dev_role
database: dev_db
schema: public
warehouse: dev_wh
user: "{{ env_var('DBT_USER') }}"
password: "{{ env_var('DBT_PASSWORD') }}"
prod:
type: snowflake
account: <orgname>-<account_name>
role: prod_role
database: prod_db
schema: public
warehouse: prod_wh
user: "{{ env_var('DBT_USER') }}"
password: "{{ env_var('DBT_PASSWORD') }}"
Recce
の挙動
recce server
を実行する際の挙動は以下のようになっている
参照 | profiles.ymlの設定項目 |
---|---|
常に環境ごとの設定値が参照されるもの | database |
コマンド実行時に指定した環境の設定値が参照されるもの |
warehouse , role
|
profiles.yml
に記載した通り、database
は比較元と比較先で異なるものを設定していても大丈夫だが、ウェアハウスとロールはコマンド実行のものとなる (おそらくユーザーも)
つまり、上記のprofiles.yml
に記載した通りの設定を行った場合、下表のようになる
実行コマンド | 実際に使用されるロール | 実際に使用されるウェアハウス |
---|---|---|
recce server |
dev_role |
dev_wh |
recce server -t prod 3
|
prod_role |
prod_wh |
例えば、dev_role
にprod_db
へのアクセス制限がない状態でrecce server
を実行すると、比較を行うクエリが権限不足で失敗してしまうので、例えば以下のいずれかで対応する必要がある
-
prod_role
にdev_db
への読み取り権限を与え、recce server -t prod
と実行するようにする -
prod_db
とdev_db
の両方に読み取り権限を持つロールrecce_role
を追加して、recce用のprofileを作る。実行はrecce server -t recce
とするrecce: type: snowflake account: <orgname>-<account_name> role: recce_role database: dev_db schema: public warehouse: recce_wh # recce用のウェアハウス user: "{{ env_var('DBT_USER') }}" password: "{{ env_var('DBT_PASSWORD') }}"
いずれも方法においても、レビューモードでは注意が必要
レビューモードでも同様にターゲットを指定して実行することが可能になっている 4
その他細かい注意点
-
プリセットで説明したrecce.ymlのprimary_keysだが、Snowflakeの場合は通常大文字で指定してやる必要がある
-
Recce
内部では、primary_keyで指定したものが、データベース上に存在するか確認しているっぽい - 現状その照合で大文字と小文字を区別しているので、小文字にすると、primary_keyがないとエラーになる
primary_keys: - CUSTOMER_ID
-
できないこと
- 参照先のDBが異なる場合は利用できない(devをDuckDB、prodをSnowflakeにする等)
- そのため、dbtの基盤を別DBに移行するというシナリオでは使用できないと思われる
- dbtでの検証を対象にしているため、DWHの移行で既存のETLをdbtにリプレイスする際の検証にも使用できない
最後に
見つけた勢いのまま書いてしまったが、いい感じのパッケージなので、今後積極的に使っていきたいと思った(いい感じを多用している)
参考
- 公式ドキュメント
- ここで、
Recce
の紹介がされていた
- ベストプラクティス
- 公式のプルリクのデモ(いい感じ)
-
返品した商品を売上から除外するように修正したため、売上は修正前に比べて小さくなったとか ↩
-
pathについて、環境ごとに違うファイルを指定することは可能だが、この場合は、
Recce
はエラーとなってしまう ↩ -
recce server
時に、--target
もしくは-t
を指定することで、実行時の環境が選べるようになっている ↩ -
レビューモードの場合は、targetオプションが効かず、デフォルトの環境を参照するようになっていると思われる。バグっぽいので、Issueで問い合わせ中 → 問い合わせた結果、すぐに修正してもらうことができた (v0.20.1)
ただ期待されていた挙動としては、stateファイル作成時の環境で実行されることっぽいので、将来的には、stateファイルにtargetの情報が含まれる + レビューモードではtargetの指定が不要( → stateファイルのtargetの情報が使用される)みたいになるかもしれない ↩