dbt-covesを用いてdbt modelファイルの生成


dbt-covesについて紹介しつつ、dbtモデルファイルの生成を試した

概要

全体的な機能について書き下しておく

ここがイケてる!dbt-coves の推しポイント

1. データのscaffold生成

dbtをやっていて一番心が折れる瞬間、それは「sources.yml を手書きしているとき」ではないでしょうか? dbt-covesの真骨頂はここにあります。

dbt-coves generate sources でデータモデルファイルの初期生成
  • DWH(Snowflake, BigQuery, Redshift)のメタデータを読み取って、sources configを自動生成してくれます。
  • **ステージングモデル(sqlファイル)とそのプロパティファイル(yml)**まで一気に作ってくれます。
  • プロパティファイルの生成にはテーブルのメタデータを参照しするので、marts層のモデルも対象にできます。
  • カラム名、データ型、全部自動入力。人間は「生成されたファイルを確認・編集するだけ」。これでsqlファイルやymlファイルの統一や、編集時のコピペ地獄から解放されます。

2. 「最強の初期構成」をコマンド一発で設定

dbt init で作られる素のプロジェクトでもある程度の設定は行われるが、認証情報やdbtプロジェクトの設定、気になるパッケージを入れるなどのymlファイルいじりが発生します。これでは快適な開発環境を構築するまで時間がかかりますよね。

dbt-coves setup によるプロジェクトの初期設定
  • このコマンド一発で、sqlfluff(SQLリンター)やyamllint、dbt-checkpointを含めたpre-commit hookのconfigが爆誕します。
  • 「あ〜、linterの設定どうするんだっけ…」と悩む時間はゼロ。最初から、後々追加したくなる機能が初期設定された環境を構築できます。
  • 特にymlやsqlなどはプログラミング言語ほどではないにせよ、柔軟に書ける。そのためlinterを早めに設定し、「インデントのルールがバラバラ」といったチーム開発での問題を撲滅すべきだ。

3. Airflowとの連携も視野に入っている

このパッケージのメンテナがdatacovesというdbt & Airflowのインテグレーション環境をもつSaaSを開発しているため、データ分析プラットフォームとしての連携も強いです。

dbt単体で完結せず、ワークフローエンジン(Airflow)でオーケストレーションする。また、データロード(fivetrans)のリソース管理も見越した機能を搭載しています。

  • Airflow DAGの生成もサポート
    • dbtのモデルを実行するためのAirflow DAG(Pythonコード)を、YMLの設定ファイルから生成する機能もあります。
    • 「sql(dbt)は書けるけどPython(Airflow)は苦手…」というアナリティクスエンジニアでも、dbt-coves経由ならパイプライン構築が容易になります。

実装

試したのはdbtのstaging modelなどの生成あたり

背景としてはdbtのsource、properties(modelのyml)を生成したいな、となった際、dbtパッケージのcodegenでは、スキーマごとにファイル分けるとき、シェル逐次処理をがんばらないといけないのがちょっとしんどかった

このあたりの機能ではdbt-osmosisが一番有名という認識だが、v1.17のまましばらくリリースされていない気配があったので、代わりとなるツールを探してみたところ、dbt-covesというツールを見つけた。実装ではそのあたりのモデルファイル生成機能に重点をおいて試していく

今回出てくるデータモデルなどを生成するツールの違いを表にすると以下のようになる

パッケージ名リポジトリスター数 (おおよそ)メンテナ用途・概要
dbt-coves~270Datacoves初期構築・ファイル生成の自動化
・ステージングSQL・プロパティファイルを物理的に生成するCLIツール。
dbt-osmosis~590Community
(z3z1ma)ファイル生成に加えて、運用・YAML同期もできる。
DWHとプロジェクトの差分を検知し、既存のYAMLへカラム追記や整理を行うCLIツール。「更新」に強い。
dbt-codegen~620dbt Labs
(公式パッケージ)Jinjaマクロで実行される。YAML生成機能はなく標準出力として生成される。dbt mcp server経由でツールとして使える

環境

  • dbt: 1.9
  • dbt-coves: 1.10.5
  • dbt-osmosis: 1.1.17
  • dbt codegen: 0.14.0
uv add dbt-coves==1.10.5

でパッケージインストール。pydanticのバージョン解決ができず以下の設定を追加するなどした

[tool.uv]
override-dependencies = [
    "pydantic>=2.7"
]

dbt project

search consoleをbigqueryに連携したデータを例に操作する

カスタムスキーマなどは設定していない

フォルダ構成はこんな感じ。生成後のファイルも含んでいる

.
├── dbt_project.yml
├── error.log
├── Makefile
├── models
   └── blog
       ├── sources
   ├── _searchconsole__exportlog.yml
   ├── _searchconsole__searchdata_site_impression.yml
   └── _searchconsole__searchdata_url_impression.yml
       └── staging
           ├── stg_searchconsole__exportlog.sql
           ├── stg_searchconsole__exportlog.yml
           ├── stg_searchconsole__searchdata_site_impression.sql
           ├── stg_searchconsole__searchdata_site_impression.yml
           ├── stg_searchconsole__searchdata_url_impression.sql
           └── stg_searchconsole__searchdata_url_impression.yml
├── package-lock.yml
├── packages.yml
├── profiles.yml
├── selectors.yml
└── .dbt_coves
    ├── config.yml
    └── templates
        ├── model_props.yml
        ├── source_props.yml
        ├── staging_model_props.yml
        └── staging_model.sql
  • dbt_project.yml
name: 'data'
version: '1.0'
config-version: 2
 
model-paths: ["models"]
seed-paths: ["seeds"]
test-paths: ["tests"]
analysis-paths: ["analyses"]
 
flags:
  require_explicit_package_overrides_for_builtin_materializations: false
 
models:
  data:
    blog:
      staging:
        +materialized: table
        +schema: staging
        +schema_suffix: ''
 
      intermediate:
        +materialized: table
        +schema: intermediate
        +schema_suffix: ''
 
      marts:
        +materialized: table
        +schema: marts
        +schema_suffix: ''
  • profiles.yml
blog:
  target: local
  outputs:
    local:
    type: bigquery
    method: service-account
    project: "{{ env_var('BIGQUERY_PROJECT_ID', 'dummy-project') }}"
    schema: blog
    keyfile: .config/searvice-account.json
    timeout_seconds: 300
    location: US

generate sources

sourceとstagingのファイルを生成する

これにより、環境ごとにstagingレイヤーでやるべき処理やクエリの書き方の統一化を図る

実行

コマンド実行は基本dbt projectディレクトリにて、またdbt-covesにパスを通した状態(.venvをactivateした状態)で行っている

以下コマンドにより、stagingのmodelファイル群sqlとyml(properties)ファイルを生成する

対話型。—no-promptというオプションを付けることで非対話的に処理もしてくれる

ここでは引数もまとめてcliで指定したが、config.ymlとして作成、設定もできる。config.ymlについては後述する

dbt-coves generate sources --project-dir ./ --profiles-dir ./ --target local \
	--schemas searchconsole --update-strategy update \
	--sources-destination models/blog/sources/_{{schema}}__{{relation}}.yml \
 	--models-destination models/blog/staging/stg_{{schema}}__{{relation}}.sql \
 	--model-props-destination models/blog/staging/stg_{{schema}}__{{relation}}.yml \
	--templates-folder .dbt_coves/templates \
 
     _ _     _
  __| | |__ | |_       ___ _____   _____  ___
 / _` | '_ \| __|____ / __/ _ \ \ / / _ \/ __|
| (_| | |_) | ||_____| (_| (_) \ V /  __/\__ \
 \__,_|_.__/ \__|     \___\___/ \_/ \___||___/
 
 
dbt-coves v1.10.5                   dbt v1.9.1
 
19:39:13  Registered adapter: bigquery=1.9.0
? Which sources would you like to generate? (Use arrow keys to mov
e, <space> to select, <a> to toggle, <i> to invert)
 » ○ [searchconsole] ExportLog
   ○ [searchconsole] searchdata_site_impression
   ○ [searchconsole] searchdata_url_impression
 
 
...
models/blog/staging/stg_searchconsole__searchdata_site_impression.sql created
Property file
models/blog/staging/stg_searchconsole__searchdata_site_impression.yml created
Property file
...

生成されたファイルがこちら。一応searchconsoleの連携データはいくつかdescription入っているはずだが、反映されなかった。そこまでの機能と動作は試さなかったが、cliのmetadata機能を経由して管理する方針らしい

  • sourceファイル
version: 2
 
sources:
  - name: searchconsole
    tables:
      - name: searchdata_site_impression
        description: ""
  • staging

sqlファイル

with raw_source as (
    select *
    from {{ source('searchconsole', 'searchdata_site_impression') }}
),
 
final as (
    select
        cast(data_date as date) as data_date,
        cast(site_url as string) as site_url,
        cast(query as string) as query,
        cast(is_anonymized_query as boolean) as is_anonymized_query,
        cast(country as string) as country,
        cast(search_type as string) as search_type,
        cast(device as string) as device,
        cast(impressions as int64) as impressions,
        cast(clicks as int64) as clicks,
        cast(sum_top_position as int64) as sum_top_position
 
    from raw_source
)
 
select * from final
 

propertiesファイル

version: 2
 
models:
  - name: searchdata_site_impression
    description: ""
    columns:
      - name: data_date
      - name: site_url
      - name: query
      - name: is_anonymized_query
      - name: country
      - name: search_type
      - name: device
      - name: impressions
      - name: clicks
      - name: sum_top_position
 

dbt-covesを用いてdbt modelのyml生成するメリット

利点としては、config.ymlでの生成ルール設定、対象モデルの絞り込みやすさ、が挙げられる

順番に解説する

config.ymlにて生成ルールの設定

dbtは柔軟なので、sourceファイルをどこにおいても認識する。設置場所や命名規則などを統一化しておくことで管理、lintの適用もしやすくなる

設定は以下

ちなみにこちらは生成コマンドがみあたらなかったのでリポジトリから持ってきて、説明通りに設置した

.dbt_coves/config.ymlに作成

https://github.com/datacoves/dbt-coves/blob/main/docs/settings.md

generate:
  sources:
    database:
      - "{{ env_var('BIGQUERY_PROJECT_ID', 'dummy-project') }}"
    # どのスキーマを対象にするか(複数指定可)
    schemas:
      - searchconsole
 
    exclude_relations:
      - ExportLog
 
    # ファイルの出力先と命名規則
    # schemaはdataset名、relationはtable名
    sources_destination: "models/blog/sources/_{{schema}}__{{relation}}.yml"
    models_destination: "models/blog/staging/stg_{{schema}}__{{relation}}.sql"
    model_props_destination: "models/blog/staging/stg_{{schema}}__{{relation}}.yml"
 
    # 既存ファイルがある場合の挙動
    update_strategy: update
 
    # SQLの中身(生成するmodelファイルのテンプレート)
    templates_folder: ".dbt_coves/templates"
 
    # JSONデータがあったらフラット化するか聞いてくれる
    flatten_json_fields: ask

templates folder以下のテンプレートファイルはコマンドで生成できる。ここでは特にいじらなかった

dbt-coves generate templates

生成対象モデルの絞り込み設定

各生成ツールにて、dbt_project.ymlにてtagを付与したmodel群のみ処理対象に含める処理を例示してみる

  • dbt-coves

tag:dbt-covesのモデルのみpropertiesを生成する。dbt cliでおなじみselectオプションを追加することで有効となる

dbt-coves generate properties --select tag:dbt-coves
...
The selection criterion 'tag:dbt-coves' does not match any
enabled nodes
No nodes selected!
 
  • osmosis

tag: osmosis付きのmodelを対象として、ここではrefactorの管理対象としたいモデルに対してコマンドを実行する。実現するには以下のようなシェルを書く

#!/bin/bash
set -e
 
# osmosisタグの付いたモデルのスキーマを対象としてコマンド実行する
targets=$(dbt ls --quiet --select tag:osmosis --resource-type model | \
  sed 's/^[^.]*\.//' | \
  sed 's/\.[^.]*$//' | \
  sort | \
  uniq)
 
for fqn_prefix in $targets; do
    echo "processing selector: $fqn_prefix"
    dbt-osmosis yaml refactor --target prod --fqn "$fqn_prefix"
done
  • codegen

tag: codegen付きのmodelを対象としてpropertiesを生成する。codegenではmodel名単位で指定するみたい。およそ、同じような雰囲気で処理している

#!/bin/bash
 
TARGET_TAG="codegen"
OUTPUT_DIR="./generated_models"
 
# 出力ディレクトリがなければ作成
if [ ! -d "$OUTPUT_DIR" ]; then
  mkdir -p "$OUTPUT_DIR"
  echo "created output_dir: $OUTPUT_DIR"
fi
 
# list for target model
MODELS=$(dbt ls --select "tag:$TARGET_TAG" --resource-type model --quiet)
 
if [ -z "$MODELS" ]; then
  echo "not found, target model"
  exit 0
fi
 
for model in $MODELS; do
  echo "generating... $model -> $OUTPUT_DIR/_$model.yml"
 
  dbt --quiet --no-use-colors run-operation generate_model_yaml \
    --args "{\"model_names\": [\"$model\"], \"upstream_descriptions\": true}" \
    | sed -n '/^version:/,$p' > "$OUTPUT_DIR/_${model}.yml"
 
done
 

おわりに

いかがでしたか? 今回はdbt の開発からリリースまでを自動化・シンプルにすツール、dbt-covesを紹介しつつ、中でも特に強力な dbt generate sources を中心に紹介しました。

このツールの真価は、単なる退屈な作業を自動化するだけではありません。config.yml で命名規則やディレクトリ構造を定義し、それを強制的に出力させることで、「誰が作っても同じ品質のコードになる(標準化)」という点にあります。

  • 面倒なセットアップは setup
  • モデルの生成は generate で自動化
  • 生成ファイルの場所や命名ルールは config で統一

これらを導入するだけで、dbtプロジェクトのメンテナンス性は格段に向上します。この記事では簡単に競合ツール(dbt-osmosis等)の比較も行いましたが、「初期構築の爆速化」という点では dbt-coves がカバーする範囲が頭1つ抜けている印象です。

運用フェーズに入ればdbt-osmosisのようなツールも選択肢に入ってきます。しかし、プロジェクトの立ち上げやリファクタリング期における dbt-coves の「圧倒的な推進力」は、一度使うと利便性に気づくはずです。 面倒な作業はツールに任せて、カオスとは無縁の dbt ライフを始めましょう。


おまけ

今回は既存プロジェクトでコマンドを試したのでsetupコマンドの出番がなかったが、試しに動かしてみた

コマンドのドキュメントもまだなかったので、手探りで動かした

dbt projectのディレクトリを環境変数で設定する export DATACOVES__DBT_HOME="$(pwd)" などとしてから

dbt-coves setupコマンドを動かす

export DATACOVES__DBT_HOME="$(pwd)"
dbt-coves setup
...
Generating artifacts using our the Datacoves template.
 
🎤 Select what you want to set up?
   done (4 selections)
🎤 Enter the dbt project directory
   .
🎤 Enter a name for your dbt project?
   dbt_coves_project
...
 

datacovesユーザー向け感が否めないし、対話型のテキストがコピーできなかったので詳しくは割愛する。dbt_projectのベースプロジェクトの生成に加え、airflow向けのpythonファイルや、ci向けの設定セットアップなどもあった

中でも生成されたpre commitの設定ファイルがとても便利そうだったので貼っておく

# .pre-commit-config.yaml
files: ^./models/
 
repos:
 
  - repo: https://github.com/dbt-checkpoint/dbt-checkpoint
    rev: v2.0.7
 
    hooks:
      - id: check-source-table-has-description
      - id: check-script-semicolon
      - id: check-script-has-no-table-name
      - id: check-script-ref-and-source
      - id: check-model-has-description
      - id: check-model-has-properties-file
      - id: check-model-has-all-columns
 
  - repo: https://github.com/sqlfluff/sqlfluff
    # this is the version of sqlfluff, needs to be updated when using a new sqlfluff version (pip show sqlfluff)
    rev: 3.1.1
    hooks:
      - id: sqlfluff-lint
        language: python
        # Need these two dependencies.
        #   sqlfluff-templater-dbt should match the version of sqlfluff above in rev (pip show sqlfluff-templater-dbt)
        #   dbt-snowflake needs to match the version in transform tab of Datacoves (pip show dbt-snowflake)
        additional_dependencies:
          [
            sqlfluff-templater-dbt==3.1.1,
            dbt-bigquery==1.9,
            dbt-core==1.9.1,
          ]
        args: [--config, "./.sqlfluff"]
 
  - repo: https://github.com/adrienverge/yamllint.git
    rev: v1.37.1
    hooks:
      - id: yamllint
        args: [-c=.yamllint]
        exclude: ^./.dbt_coves/templates
 

参考

公式リポジトリ