🐦

dbtでスキーマのみ管理し、外部アプリからデータ挿入する方法

に公開

dbtでスキーマのみ管理、外部アプリからデータ挿入する方法

背景

機械学習プロジェクトにおいて、以下のようなデータマートの要件が発生しました。

  • データマートのデータを入力として利用
  • 機械学習した結果はテーブルに保存

この要件では、入力データはデータマートで用意し、出力データは、テーブルのみ用意しておきます。
なので、dbt runを実行しても既存データが上書きされないことが重要です。通常のmaterialized="table"では、drop and createが実行されるため、外部アプリケーションがdbt runで構成したtableに対して、insertしたデータも、dbt runが実行されると削除されてしまいます。

今回はmaterialized='incremental'を使用してこの課題を解決しました。

スキーマのみ管理する実装方法

モデル設定

{{ 
  config(
    materialized='incremental',
    incremental_strategy='append',
    on_schema_change='ignore',
    post_hook=[
      "grant all on {{ this }} to role prod_role",
    ]
  ) 
}}

select
    cast(null as varchar(5)) as id,
    cast(null as varchar(50)) as name
where false  -- falseにすることでレコードは作成されない

SQLの説明

  • materialized='incremental': incrementalモデルを指定
  • incremental_strategy='append': 新しいレコードの追加方法を指定。今回は毎回0レコードなので、appendで問題ありません
  • on_schema_change='ignore': スキーマ変更時の挙動をignoreに指定
    • カラム追加時: テーブル上に反映されない
    • カラム削除時: dbt runが失敗する
    • スキーマ変更が必要な場合は、アプリケーション側の仕様変更に合わせてdbt run --full-refreshでincrementalモデルを再生成する

まとめ

読んでいただき、ありがとうございました。

where falseの使い方は知らなかったので、今回のケースで活用できて良かったです。データは、全てをdbtで完結させたいという願望もあり、管理ができて満足しています。

感覚的には、Reverse ETLの受け手側に近いアーキテクチャでしょうか。dbtでスキーマを管理し、外部アプリケーションがデータを挿入するという役割分担が明確になって、保守性も向上しました。

Discussion