dbt で生成される catalog.json は、実データベース上のリレーションとカラムの物理情報を集約したアーティファクトです。schema.yml で書いた説明や tests などのロジカルな情報(manifest.json)と組み合わせることで、信頼できるデータカタログを構築できます。
本稿では、catalog.json の正しい位置づけと生成・運用、外部カタログとの連携パターン、そして Analytics Engineer 試験で問われやすいポイントを、実務目線で整理します。
catalog.json は、dbt docs generate 実行時に target ディレクトリへ出力されるアーティファクトで、アダプタ(Snowflake、BigQuery、Databricks など)が提供するメタデータ API を用いて、実スキーマ上のリレーションとカラム情報を収集します。含まれる代表的情報は、データベース/スキーマ/テーブル名、カラム名・型、コメント、(アダプタにより)行数や統計の一部です。フィールドはバージョンやアダプタにより増減しますが、物理メタデータの集約という役割は安定しています。
docs サイトの生成には manifest.json(ロジカル情報)と catalog.json(物理情報)の両方が使われます。catalog.json 単体ではリネージやドキュメント(description)は不十分で、manifest.json と突き合わせて初めて完全なカタログになります。
| アーティファクト | 主な内容 | 主用途 |
|---|---|---|
| catalog.json | 物理メタデータ(DB/スキーマ/テーブル/カラム、型、コメント、一部統計) | 外部カタログへの同期、docs の物理側情報 |
| manifest.json | ノード定義、依存関係、プロパティ(description、tests、sources、exposures) | リネージ、ドキュメンテーション、依存解析 |
| run_results.json | 直近の実行結果(ステータス、実行時間、メッセージ) | パイプライン健全性、SLA/品質の監視 |
docs generate によるアーティファクト生成の流れ
catalog.json の生成と確認(CLI)
dbt deps
# 必要に応じてモデルを実行(catalog は実テーブル照会。未作成だと取得できない場合あり)
dbt run --select my_model
# ドキュメント生成(manifest.json と catalog.json を出力)
dbt docs generate --target-path target
# ローカルで閲覧
dbt docs serve --port 8080 --target-path target
# 生成物を確認
ls -1 target | grep -E 'manifest|catalog'モデルやカラムの説明は schema.yml に記述します。説明文や tests、meta は manifest.json に入り、catalog.json は実スキーマを照会して取得したカラム型やコメントなどを持ちます。docs サイトでは、両者がマージされ、カラム説明(ロジカル)とカラム型(物理)が同一画面に表示されます。
docs ブロック(.md で定義し doc() で参照)も manifest.json 側の情報です。結果として、catalog.json は"事実の自動収集"、manifest.json は"意図の宣言"という役割分担になります。
| 情報 | 格納先 | 表示例 |
|---|---|---|
| モデル説明 | manifest.json(properties) | テーブル概要セクションに表示 |
| カラム型・コメント | catalog.json(columns) | カラム詳細の型・コメント欄に表示 |
| tests(unique, not_null 等) | manifest.json(tests) | docs では該当カラムの Quality 情報に反映 |
ロジカル情報と物理情報のマージ
schema.yml (description/tests) catalog.json (types/comments)
\ /
\ /
v v
manifest.json catalog.json
\ /
v v
docs siteschema.yml と docs ブロックの例
# models/orders/schema.yml
version: 2
models:
- name: fct_orders
description: "受注のファクトテーブル。日次の粒度で集計される"
columns:
- name: order_id
description: "受注ID(ユニーク)"
tests:
- unique
- not_null
- name: order_total
description: "受注金額(税抜)"
meta:
pii: false
docs:
node_color: blue
# docs/blocks.md
{% docs fct_orders_notes %}
リファレンス: 売上確定ロジックは会計チーム合意済み。
{% enddocs %}
# models/orders/fct_orders.sql
select * from {{ ref('stg_orders') }}
-- description は manifest.json、型は catalog.json に載る外部データカタログ連携では、基本的に manifest.json と catalog.json の両方を取り込みます。catalog.json からは物理名・カラム型を、manifest.json からは説明・所有者・リネージ・tests・exposures を取得し、統合して登録します。
注意点として、ephemeral モデルは実テーブルを作らないため、catalog.json には現れません。一方、manifest.json にはノードとして存在します。リネージ上は重要でも、物理カタログには載らないケースがある点を押さえてください。
| 観点 | catalog.json | manifest.json |
|---|---|---|
| リレーション有無 | 実在する物理のみ(アダプタが返す対象) | すべてのリソース(models, sources, seeds, exposures 等) |
| 情報粒度 | テーブル/ビュー/カラム中心(型・コメント・一部統計) | プロパティ、依存関係、ドキュメント、tests |
| 主な不足 | リネージ、記述、tests は持たない | カラム型・統計などの物理情報 |
三位一体で docs を構成
catalog.json のノード例(抜粋)
{
"nodes": {
"model.my_proj.fct_orders": {
"database": "ANALYTICS",
"schema": "MART",
"name": "fct_orders",
"resource_type": "model",
"relation_name": "ANALYTICS.MART.FCT_ORDERS",
"columns": {
"ORDER_ID": {"name": "ORDER_ID", "type": "NUMBER", "comment": "受注ID"},
"ORDER_TOTAL": {"name": "ORDER_TOTAL", "type": "NUMBER", "comment": "受注金額"}
}
}
}
}多くのデータカタログ(例: DataHub、Amundsen、Collibra、Alation)は、dbt アーティファクトの取り込みに対応またはコミュニティ実装を持ちます。一般的には manifest.json と catalog.json のセットをアップロードまたは参照し、モデルの説明・所有者(manifest)とカラム型・コメント(catalog)を統合してエンティティを更新します。
連携方式は大きく、ポーリング(ファイル置き場を定期取得)、プッシュ(CI/CDからAPI呼出)、和解(既存スキーマメタデータに dbt 情報をマージ)の3パターン。最初はプッシュが扱いやすく、差分更新は manifest の node_version やチェックサム、ファイル更新時刻などをキーに実装します。
| 方式 | メリット | 留意点 |
|---|---|---|
| プッシュ(API) | 即時反映・失敗検知が容易 | ネットワーク/認可設定が必要 |
| ポーリング(ストレージ) | 疎結合・拡張しやすい | 遅延・重複処理の制御が必要 |
| 和解(マージ) | 既存運用と整合性を保てる | キー設計・重複解消ロジックが必要 |
外部カタログ連携のデータフロー
catalog.json を読み込み API へプッシュ(最小例)
import json, os, requests
ARTIFACT_DIR = os.environ.get("ARTIFACT_DIR", "target")
CAT_PATH = os.path.join(ARTIFACT_DIR, "catalog.json")
MANI_PATH = os.path.join(ARTIFACT_DIR, "manifest.json")
with open(CAT_PATH, "r", encoding="utf-8") as f:
catalog = json.load(f)
with open(MANI_PATH, "r", encoding="utf-8") as f:
manifest = json.load(f)
# 例: カラム定義を抽出して送信(適宜スキーマ合わせ)
payload = []
for node_id, node in catalog.get("nodes", {}).items():
cols = node.get("columns", {})
for c in cols.values():
payload.append({
"node_id": node_id,
"relation": node.get("relation_name"),
"column": c.get("name"),
"type": c.get("type"),
"comment": c.get("comment")
})
resp = requests.post("https://catalog.example.com/api/dbt/columns", json=payload, timeout=30)
resp.raise_for_status()
print("uploaded:", len(payload))catalog.json はデータベースの現況を反映します。更新頻度はモデルの更新頻度と利用部門のニーズに合わせ、少なくとも日次での再生成を推奨します。CI ではプルリク時に docs generate を走らせて差分を可視化し、本番リリース後に本番環境の catalog.json を確定させます(環境ごとに分離して保存)。
セキュリティ面では、PII カラムに対するコメント公開の可否を決め、外部連携前にフィルタリングします。統計情報はアダプタ依存であり、row_count 等が欠損することもあるため、SLA 監視には run_results.json など別のソースと併用します。
| 運用項目 | 推奨 | 補足 |
|---|---|---|
| 更新頻度 | 日次(変更が多い場合は随時) | CI は最小構成、本番は確定版を保管 |
| 保存先 | オブジェクトストレージに世代管理 | 環境/日付/コミットIDで階層化 |
| 公開ポリシー | PII コメントの除去/マスク | meta やタグで制御、連携前にフィルタ |
CI/CD でのアーティファクト運用
CI で docs 生成と成果物保管(例: Bash)
# 環境変数で接続先を切替
export DBT_TARGET=prod
export DBT_PROFILES_DIR=.
# 依存取得と実行(必要に応じて)
dbt deps
# 生成(出力先を明示)
dbt docs generate --target ${DBT_TARGET} --target-path artifacts/${DBT_TARGET}/$(date +%F)
# 成果物をアップロード(擬似コマンド)
aws s3 sync artifacts/${DBT_TARGET}/$(date +%F) s3://my-bucket/dbt-artifacts/${DBT_TARGET}/$(date +%F)Analytics Engineer 試験では、dbt ドキュメンテーションとアーティファクトの役割理解が頻出です。catalog.json と manifest.json の違い、docs generate/serve の挙動、exposures によるダッシュボードの記述、tests の定義範囲などを整理しましょう。
落とし穴として、ephemeral モデルが catalog.json に現れない点、run_results.json と catalog.json の混同、docs ブロックと description の使い分けが挙げられます。どの情報がどのファイルに入るかを即答できる状態にしておくと安心です。
| 問われやすいテーマ | 覚えるキーワード | 間違えやすい対比 |
|---|---|---|
| アーティファクトの役割 | catalog=物理, manifest=ロジカル | catalog vs run_results |
| BI 連携メタ | exposures | sources vs exposures |
| ドキュメント | schema.yml の description / docs ブロック | コメント(物理) vs 説明(ロジカル) |
どの質問にどのファイルで答えるか
物理型は? ------> catalog.json
説明/所有者は? -> manifest.json
実行は成功? ---> run_results.jsonjq で catalog.json から特定テーブルのカラム型を抽出
TABLE_ID="model.my_proj.fct_orders"
cat target/catalog.json \
| jq -r --arg id "$TABLE_ID" '.nodes[$id].columns | to_entries[] | "\(.value.name),\(.value.type)"'Analytics Engineer
問題 1
dbt でモデルやカラムの説明は schema.yml に書いた。外部データカタログへカラム型とコメントを連携したい。最も適切に情報源となるアーティファクトはどれか。
正解: A
catalog.json は実データベースの物理メタデータ(テーブル/カラム、型、コメント等)を集約する。run_results.json は直近実行結果、packages.yml は依存パッケージ宣言、profiles.yml は接続設定のため、本設問の用途には不適切。
catalog.json はいつ更新されるか。モデルを実行しなくても最新になるか。
dbt docs generate 実行時に更新されます。アダプタがメタデータを取得できる場合は、モデルを直前に実行しなくても、データベース上に既に存在するリレーションについて最新の物理情報が収集されます。未作成のリレーションは取得対象になりません。
ephemeral モデルや CTE も catalog.json に載るか。
ephemeral は物理リレーションを作らないため catalog.json には現れません(manifest.json にはノードとして記録されます)。CTE も同様に中間物理オブジェクトではないため対象外です。
catalog.json に含まれる統計(row_count など)が null になるのはなぜか。
統計の提供はアダプタ依存で、取得できない項目は null になります。これは異常ではなく仕様です。SLA 監視やボリューム検証は run_results.json や別途のクエリで補完します。
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)、設定優先度...