dbt は実行ごとに JSON アーティファクトを target/ 配下に生成します。なかでも manifest.json、run_results.json、catalog.json は可観測性・ドキュメント・CI 連携の中心です。
本稿は dbt docs(https://docs.getdbt.com/)に沿って、試験で問われやすい観点と現場での運用ノウハウをまとめます。バージョン差異に依存しやすい細目は注意書きを添え、安定的に通用する読み方を優先します。
dbt はコマンドの実行後、target/ に複数の JSON を出力します。実行計画とリネージは manifest.json、実行結果は run_results.json、テーブル/カラムの型や統計は catalog.json が担います。これらは可視化(dbt docs)、品質監視(CI、SLA 検証)、データカタログ連携の基礎データになります。
覚えるコアは次の3点: 1) manifest はグラフ(依存関係とノード定義)、2) run_results は各ノードの実行ステータスと所要時間、3) catalog は生成環境のスキーマ情報。いずれも JSON で、generated_at と metadata を持つのが通例です。
| アーティファクト | 生成コマンド例 | 主な内容 | 代表用途 |
|---|---|---|---|
| manifest.json | dbt parse / dbt run / dbt docs generate | ノード定義・依存関係・リネージ | 影響範囲解析、ドキュメント、選択子検証 |
| run_results.json | dbt run / test / build 直後 | 各ノードの実行結果・所要時間・エラー | CI 合否、SLA 監視、フレーク検知 |
| catalog.json | dbt docs generate | テーブル/ビュー/カラムの型とメタデータ | データ辞書、型監査、BI リンク付け |
アーティファクトの生成と活用フロー(概念図)
最小限の生成チェック(シェル)
dbt run --select my_model
ls -1 target | grep -E 'manifest|run_results|catalog'
# docs 情報を最新化
dbt docs generatemanifest.json はプロジェクトのグラフを表現します。各ノード(model, seed, snapshot, test, exposure, source, macro など)のメタデータ、ファイルパス、materialized、depends_on、および child_map/parent_map が含まれます。試験では「影響範囲の特定」と「選択子の評価」に結び付けて理解しておくと得点源です。
フィールドはバージョンで増減しますが、nodes, sources, child_map/parent_map, generated_at, metadata は安定的に登場します。adapter やパッケージの差異は metadata に含まれることが多く、移植性評価に使えます。
| フィールド(例) | 型/例値 | 用途 | 安定度(目安) |
|---|---|---|---|
| nodes | dict | model/test 等のノード定義 | 高 |
| sources | dict | source 定義とカラム | 高 |
| child_map / parent_map | dict[str, list[str]] | 全体のリネージ探索を高速化 | 中〜高 |
| generated_at | ISO 8601 | 生成時刻の追跡 | 高 |
| metadata.adapter_type | str | 実行基盤の種類(例: snowflake, bigquery) | 中 |
依存関係の方向(上流→下流)
manifest.json から影響範囲を列挙(Python)
import json
from collections import deque
with open('target/manifest.json') as f:
mf = json.load(f)
child_map = mf.get('child_map', {})
start = 'model.my_project.fct_orders'
visited, q = set([start]), deque([start])
while q:
n = q.popleft()
for c in child_map.get(n, []):
if c not in visited:
visited.add(c)
q.append(c)
print('\n'.join(sorted(visited))) # fct_orders の下流に影響するノード一覧run_results.json は直近のコマンド(run/test/build 等)に関する結果を格納します。各 result には status(success, error, skipped など)、execution_time、timing(compile/execute の内訳)、failures(test の失敗件数など)を含みます。CI ではここを機械判定に使い、SLA 監視では遅延やフレークの兆候を検出します。
注意点として、run_results は“直近実行”のスナップショットです。履歴分析をするなら毎回収集・保管(オブジェクトストレージや DWH へ COPY)する運用が必要です。
| フィールド(例) | 型/例値 | 用途 | 備考 |
|---|---|---|---|
| results[] | list | 各ノードの実行結果 | status, timing, execution_time |
| elapsed_time | float 秒 | 全体の所要時間 | 壁時計時間 |
| generated_at | ISO 8601 | 生成時刻 | 監査に利用 |
| args | dict | 実行時引数 | 選択子など |
| metadata | dict | 環境/アダプタ情報 | 再現性確保に活用 |
CI における合否判定の流れ
run_results.json を要約(Python)
import json, sys
from collections import Counter
with open('target/run_results.json') as f:
rr = json.load(f)
status = Counter(r.get('status', 'unknown') for r in rr.get('results', []))
mean_time = sum(r.get('execution_time', 0.0) for r in rr.get('results', [])) / max(1, len(rr.get('results', [])))
print('status summary:', dict(status))
print('mean execution_time(sec):', round(mean_time, 2))
errors = [r for r in rr.get('results', []) if r.get('status') == 'error']
if errors:
print('ERROR DETAILS:')
for e in errors:
node = e.get('unique_id')
msg = e.get('message', '')
print(f'- {node}: {msg[:200]}')
sys.exit(1)catalog.json は dbt docs generate により作成され、データベース上の実体(モデル、ソース)のカラムごとの型やコメント、場合により統計情報(例えば行数推定)を含みます。これを manifest と突き合わせると、論理定義と物理実装の差異検知が可能になります。
アダプタにより data_type 名称や統計の粒度は変わります。試験では「catalog は docs generate によって生成される」「列情報と型を提供する」点を確実に押さえてください。
| 要素 | 例 | 活用ポイント | 注意 |
|---|---|---|---|
| nodes[unique_id].columns | order_id: {data_type: NUMBER} | 列型のドキュメント化 | アダプタ依存の型名 |
| metadata.adapter_type | snowflake/bigquery/redshift 等 | 接続先ごとの差異把握 | マルチクラウドでの比較に便利 |
| generated_at | ISO 8601 | スナップショット時点の明示 | 遅延検知に活用 |
manifest × catalog の突合イメージ
manifest.nodes[model.fct_orders] ----join on unique_id---- catalog.nodes[model.fct_orders]
| logical config | physical columns/typescatalog と manifest を突合し、型差異を検出(Python)
import json
with open('target/manifest.json') as f: mf = json.load(f)
with open('target/catalog.json') as f: cg = json.load(f)
m_nodes = mf.get('nodes', {})
c_nodes = cg.get('nodes', {})
for uid, m in m_nodes.items():
if not uid.startswith('model.'): # モデルに限定
continue
c = c_nodes.get(uid)
if not c:
continue
m_cols = (m.get('columns') or {}).keys()
c_cols = (c.get('columns') or {}).keys()
missing = set(m_cols) - set(c_cols)
if missing:
print(f'[WARN] not in catalog: {uid} -> {sorted(missing)}')アーティファクトは“保管して活かす”が基本です。CI で run_results を収集し、S3/GCS へ保存してから DWH にロードすると、ジョブ安定性や回帰遅延のトレンドが取れます。manifest は Pull Request ごとの差分比較で影響範囲レビューを自動化できます。catalog はデータ辞書の更新トリガに利用します。
dbt Cloud/OSS どちらでもパターンは同じですが、保管と参照の運用設計(命名、保持期間、メタデータ付与)が品質を左右します。
| ユースケース | 参照アーティファクト | 要点 | 失敗パターン回避 |
|---|---|---|---|
| 合否判定(CI) | run_results.json | status 集計と閾値 | 直近のみのため必ず保管 |
| 影響範囲レビュー | manifest.json | child_map/parent_map で差分可視化 | unique_id の安定管理 |
| データ辞書自動更新 | catalog.json + manifest.json | 物理型と論理定義の突合 | アダプタ差分の正規化 |
CI でのアーティファクト保管パイプライン
GitHub Actions 例(YAML 抜粋)
jobs:
dbt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: '3.11' }
- run: pip install dbt-core dbt-bigquery
- run: dbt deps && dbt build --fail-fast
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dbt-target
path: target/*.jsonAnalytics Engineer 試験では、アーティファクトの生成タイミングと用途の切り分けが頻出です。特に「catalog は docs generate」「run_results は直近実行のみ」「manifest はリネージの情報源」の3点を即答できるようにしましょう。
また、unique_id の安定性、depends_on と child_map の違い、invocation_id の用途を言語化できると加点につながります。バージョン固有の細目よりも、ファイル間の役割分担を優先して覚えるのが安全です。
| 問いの型 | 正答のカギ | 誤答パターン | ワンポイント |
|---|---|---|---|
| 生成タイミング | docs generate で catalog | run で catalog と誤認 | manifest は parse/run でも更新される |
| 用途の切り分け | run_results は合否/時間 | manifest と混同 | status, execution_time を根拠に |
| リネージ探索 | child_map/parent_map | depends_on の片方向のみ | 双方向で使い分ける |
覚え方ミニマップ
manifest = グラフ
run_results = 成否/時間
catalog = 型/カラム
→ 役割で暗記し、生成タイミングで確証を取るunique_id から人間可読名へ(Python)
import json
mf = json.load(open('target/manifest.json'))
uid = 'model.my_project.fct_orders'
node = mf['nodes'][uid]
print(node.get('name'), node.get('original_file_path'))Analytics Engineer
問題 1
dbt プロジェクトでテーブルの列型が期待どおりかを自動チェックし、差分があればドキュメントを更新したい。最も適切なアーティファクトの組み合わせはどれか?
正解: A
列型の実体は catalog.json に、論理定義や命名・説明は manifest.json にある。両者を unique_id で突合すれば、型やカラムの差分を検出しつつドキュメント更新に反映できる。run_results.json は実行結果であり型比較には不適。catalog 単独では論理定義との差を判断できない。
docs generate を実行せずに catalog.json は更新される?
いいえ。catalog.json は dbt docs generate(内部でデータベースをインスペクト)によって生成・更新されます。dbt run だけでは更新されません。
run_results.json はどのくらい保持すべき?
運用要件次第ですが、SLA 監視や回帰検知を行うなら実行ごとに外部ストレージへ退避し、少なくとも数週間〜数カ月の履歴を保持するのが一般的です。run_results は直近実行のスナップショットであり、上書きされます。
manifest.json の depends_on と child_map の違いは?
depends_on は各ノード定義内にある“そのノードが依存する上流ノード”のリストです。child_map はプロジェクト全体に対する“下流ノード”のインデックスで、特定ノードの影響範囲を即時に引けます。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
dbt Model の基礎: SQL で定義する変換の最小単位
Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...
dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点
dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...
dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点
dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...
dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト
Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....
dbt_project.yml の読み方:主要設定と命名を最短で掴む
dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...