❄️

dbt差分があるモデルだけ加工しようとしたらちょっとハマった話

2024/04/05に公開

背景

筆者のデータ基盤の軽い説明や表題に関連するやりたいことを書いていきます。
まず環境をざっと書くと以下の感じ

  • データ基盤は基本snowflake上に乗っかっている
  • データの加工はdbtでやっている

以上のような環境で、最近は開発環境をよくしたりデータオブザーバビリティを向上させたりといったことに注力していきたいと考えていました。その一環で、まずはdbtのモデル開発時、リリース前にCIでdbt runを走らせれるようにすることを実現できるよう動いていました。
なんでそんなことやろうとするの?というと、弊社のdbtの開発環境は、手元から開発環境用に用意されたsnowflakeのデータベース上でdbt runを実行できるようになっていて、開発中は主にそこで動作確認をしていたのですが、リリースしてから dbt runに失敗することに気づいて急いで修正パッチを当てるということがちょこちょこ起きていてそこに課題を感じていました。
本番での加工に失敗したのに気づいてから修正しても再度本番でdbt runし直す必要があるため余計な手間が掛かるし、修正に時間がかかればかかるほど対応がめんどくさくなっていきます。
そのため、リリースをする前に変更を加えたモデルの加工が成功するか試せるような環境をCIで構築したいと考えていました。

state:modifedで差分があるモデルだけ加工する

CIで毎回全てのモデルの加工を走らせていては時間もかかりますし、コンピュートリソースを無駄に使うことになるのでお金ももったいないです。なので加工したいモデルだけ加工させたいですよね。
そんなときに便利なのが state:modifiedというモデルの選択の方法です。

https://docs.getdbt.com/reference/node-selection/methods#the-state-method

dbtコマンドを実行する際に --select 'state:modified' --state /path/to/stateとすることで、--stateで指定したディレクトリに置かれたmanifest.jsonと実行時に生成されるmanifest.jsonを比較して、差分があるモデルだけ加工を走らせてくれるというまさに今回のようなユースケースにはうってつけのセレクターメソッドが用意されていました。
ちなみに state:modified+とすることで差分があるモデルに依存するモデルも選択することができます。変更したモデルに依存したモデルもちゃんと加工できるかな?は気になるポイントなので自分はつけてます。

比較するマニフェストファイルの用意をどうしてるか

今回の本題的にあまり大事な話ではないのであまり詳細には書きませんが、state:modifiedを使うときは比較する用のマニフェストファイルを用意する必要があります。今回は本番で動いている最新のマニフェストファイルと比較がしたいのでそいつをCI上で扱えるようにします。具体的にどうしてるかというと

  • PRをmasterへmergeした際にdbt compileをし、s3にtarget/の中身をアップロードする
  • CIで差分だけビルドするワークフローの最初にs3からmanifest.jsonを取ってくる

という感じでそんな複雑なことはしてません。

変更を加えてないモデルも加工が何故かされてしまう

state:modified+でやりたいことできるやん!勝った!第3部完!って感じでおもむろに適当なモデルに適当な変更をしdbt run --select 'state:modified+' --state /path/to/stateをしてみたのですが、現実はそんなに甘くありませんでした。
なぜか変更してないモデル(しかも全部じゃない)も加工が走っていてどういうこと????となりました。

原因

manifest.jsonとにらめっこしたりドキュメントを読み漁ったりした結果、原因はこれでした。

https://zenn.dev/pei0804/articles/dbt-snowflake-dynamic-warehouse

筆者のデータ基盤も、めちゃめちゃ量が多い生ログから対したサイズじゃないデータまで色々扱うのでモデルごとにsnowflakeのwarehouseを指定できるような状態にしていました。
で、モデルのconfigでsnowflake_warehouse=xxxxとwarehouseを指定する記述をすると、manifest.jsonの各モデルのメタデータが記述されている部分にwarehouseに関する記述も反映されます。

{
  "model.hoge.huga": {
    // 本来は他にも色々フィールド生えてるけどみやすさのために抜粋
    "config": {
      // 本来は他にも色々フィールド生えてるけどみやすさのために抜粋
      "snowflake_warehouse": "XXXXX_WH_S",
    }
  }
}

このsnowflake_warehouseの設定が、本番とCIで違うために差分があるとみなされて加工が走っていたというのが原因でした。

差分を見る対象を絞る

上記の問題をどう解消したかというと、マニフェストファイルの中で差分を見る範囲を絞ることで解決しました。

https://docs.getdbt.com/reference/node-selection/methods#the-state-method

公式ドキュメントを読むとmanifest.jsonのどの部分を見ているかというのが説明されています。
今回はモデルやテスト、マクロのSQLに変更があったときに加工が実行されてくれればいいのでstate:modified.bodystate:modified.macrosを指定することにしました。

Discussion