🏷️

Snowflakeにおけるdbtのタグ管理を自動化!dbt-elementaryを活用したvalidationの仕組み

に公開

この記事は、ナウキャスト Advent Calendar 2025 の1日目の記事です。

はじめに

こんにちは。ナウキャストでデータエンジニアをしている島尻です。

データ基盤の開発・運用の現場において、dbt(data build tool) を活用するケースは多いと思います。私が参画しているプロジェクトでも dbt を導入しており、ジョブの実行制御のために dbt の tags を活用しています。

この tags 機能は非常に便利ですが、開発者が dbt の model に対して自由に設定ができてしまいます。そのため、新しい model を追加して tags を付与する際にタイプミスをしてしまったり、設計にない tags を開発者が勝手に追加してしまったりということがあり得ます。

そのため、tags を利用する場合は、早めに設計を固めて validation の仕組みを整備することが重要と考えます。(そもそもディレクトリ指定などで事足りる場合は、tags の利用を最小限にするという選択も必要です)

本記事ではそんな dbt tags の validation の実装例を紹介します。

なお、先にネタバレをしておくと、以下の記事の内容を大いに参考にさせていただきました。こちらを Snowflake 用に置き換えて書いています。
https://zenn.dev/analytics_eng/articles/22ac854a6fd501

実装内容のサマリ

今回実装した仕組みは 「許可された tags 以外が使われていないか」を CI(継続的インテグレーション)上で自動的に検証する というものです。

dbt の基本機能である seed や test に加えて、dbt の Data Observability のパッケージである dbt-elementary を組み合わせて実装しています。なお、CI は GitHub Actions で実行する前提です。

CI パイプラインの全体像は以下の通りです。

実装の詳細

ここからは具体的な実装内容を紹介します。

dbt seed: 許可された tags の一覧を定義

dbt seed を利用して、「どの tags が有効なのか」を定義するマスタデータを作成します。開発者側で簡単に追加・PR上でレビューがしやすいように、seedのCSVファイルで定義します。

以下のようなイメージです。
※連携元システム別、DWH のレイヤー別、実行頻度別で tags を設計している例

seed_tag_description.csv
tag_name,description,tag_group
system/systemA,システムAのモデル,system
system/systemB,システムBのモデル,system
layer/staging,ステージング層のモデル,layer
layer/intermediate,中間層のモデル,layer
layer/mart,マート層のモデル,layer
schedule/daily,日次実行モデル,schedule
schedule/monthly,月次実行モデル,schedule

これまで使われていない新たな tags を付与する場合には、この seed ファイルにレコードを追加する必要があります。

dbt-elementary: 現在の tags 情報を取得

dbt の各 model で付与されている tags の一覧を取得するために、dbt-elementary パッケージを利用します。

今回は dbt_models というメタデータテーブルを利用します。dbt-elementary の利用用途が tags の validation のみの場合、dbt run --select elementary.edr.dbt_artifacts.dbt_models という形で指定して実行することで、この dbt_models テーブルのみを生成できます。

このテーブルには dbt Project 内の全 model のメタデータが格納されており、tags カラムに dbt tags の情報が配列形式で保存されます。

例えば、先述の seed_tag_description.csv を元に tags をつけている dbt model が存在する場合、以下のようなテーブルが作成されます。(2カラム、関連レコードのみ抜粋)

UNIQUE_ID TAGS
model.test_dbt_project.table1 ["system/systemA", "layer/staging", "schedule/daily"]
model.test_dbt_project.table2 ["system/systemA", "layer/intermediate", "schedule/daily"]
model.test_dbt_project.table3 ["system/systemB", "layer/staging", "schedule/daily"]

UNIQUE_IDの部分は、model.{dbt_project.ymlで定義されたproject name}.{テーブル名}となっています。

検証用の model 作成

「現在の全 model の tags」と「許可された tags(seed 定義)」を比較し、許可されていない tags を持っている model を抽出する View を作成します。

以下は Snowflake での実装イメージです。(config は省略)

metadata_dbt_tags_information.sql
WITH
    tag_list AS (
        SELECT
            tag.value::string as tag,
            listagg(alias, ', ') WITHIN group (
                ORDER BY unique_id
            ) AS related_model_sample
        FROM
            {{ ref("dbt_models") }},
            LATERAL FLATTEN(input => parse_json(tags)) tag
        GROUP BY tag
    ),

    final AS (
        SELECT *
        FROM tag_list
        LEFT JOIN {{ ref("seed_tag_description") }} USING (tag)
    )

SELECT *
FROM final
schema.yml
version: 2

models:
  - name: metadata_dbt_tags_information
    description: "List of dbt tags with sample related models and seed-based descriptions"
    columns:
      - name: tag
        description: "dbt tag"
        tests:
          - not_null
          - unique
          - relationships:
              to: ref('seed_tag_description')
              field: tag
      - name: description
        description: "Description maintained in seed_tag_description"
        tests:
          - not_null

以下は実際に作成される View のイメージですが、許可されていない tag(seed_tag_description に存在しない tag)が使用されている場合、descriptiontag_group カラムが NULL になります。

正常なケース(すべての tag が許可されている場合):

tag related_model_sample description tag_group
system/systemA model.test_dbt_project.table1, model.test_dbt_project.table2 システムAのモデル system
system/systemB model.test_dbt_project.table3 システムBのモデル system
layer/staging model.test_dbt_project.table1, model.test_dbt_project.table3 ステージング層のモデル layer
layer/intermediate model.test_dbt_project.table2 中間層のモデル layer
schedule/daily model.test_dbt_project.table1, model.test_dbt_project.table2, model.test_dbt_project.table3 日次実行モデル schedule

dbt test で失敗するケース(許可されていない tags が使用されている場合):

tag related_model_sample description tag_group
system/systemA model.test_dbt_project.table1, model.test_dbt_project.table2 システムAのモデル system
system/systemB model.test_dbt_project.table3 システムBのモデル system
system/systemC model.test_dbt_project.table4 NULL NULL
layer/staging model.test_dbt_project.table1, model.test_dbt_project.table3 ステージング層のモデル layer
layer/intermediate model.test_dbt_project.table2 中間層のモデル layer
layer/unknown model.test_dbt_project.table5 NULL NULL
schedule/daily model.test_dbt_project.table1, model.test_dbt_project.table2, model.test_dbt_project.table3 日次実行モデル schedule

上記の例では、system/systemClayer/unknown という許可されていない tag が使用されているため、descriptiontag_groupNULL となり、schema.yml で定義された not_null テストが失敗します。また、relationships テストも失敗します。

CI のワークフローへの組み込み

具体的なワークフローの yaml ファイルの例は割愛しますが、GitHub Actions の CI ジョブとして定義する際は、以下の流れでコマンドを実行していく形となります。

  • dbt run --select elementary.edr.dbt_artifacts.dbt_models
  • dbt seed --select seed_tag_description
  • dbt run --select metadata_dbt_tags_information
  • dbt test --select metadata_dbt_tags_information

PR 作成後に tags の validation チェックが走り、許可されていない tags が使用されている場合は自動的に CI エラーになるようなイメージです。これにより、tags の品質向上、レビュー負荷の軽減を図ることができます

Makefile 等で一連のコマンドを定義しておくと、ローカルで validation を試行してから PR にあげる、というプロセスが踏めるようになり、コマンド管理もできるので便利です。

まとめ

本記事では dbt-elementary や seed を利用して dbt tags の validation を行う仕組みをご紹介しました。
dbt tags は何も考えずに導入すると無法地帯になるリスクがあるため、利用する場合は tags の整合性担保や PR レビュー負荷の軽減のために、今回のような validation の仕組みを早めに導入することをおすすめします!

Finatext Tech Blog

Discussion