dbt-covesについて紹介しつつ、dbtモデルファイルの生成を試した
概要
全体的な機能について書き下しておく
ここがイケてる!dbt-coves の推しポイント
1. データのscaffold生成
dbtをやっていて一番心が折れる瞬間、それは「sources.yml を手書きしているとき」ではないでしょうか?
dbt-covesの真骨頂はここにあります。
dbt-coves generate sources でデータモデルファイルの初期生成
- DWH(Snowflake, BigQuery, Redshift)のメタデータを読み取って、
sourcesconfigを自動生成してくれます。 - **ステージングモデル(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 | ~270 | Datacoves | 初期構築・ファイル生成の自動化 |
| ・ステージングSQL・プロパティファイルを物理的に生成するCLIツール。 | |||
| dbt-osmosis | ~590 | Community | |
| (z3z1ma) | ファイル生成に加えて、運用・YAML同期もできる。 | ||
| DWHとプロジェクトの差分を検知し、既存のYAMLへカラム追記や整理を行うCLIツール。「更新」に強い。 | |||
| dbt-codegen | ~620 | dbt 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.sqldbt_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: USgenerate 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: asktemplates 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
参考
公式リポジトリ