青の統計学-DS Playground-

source 定義:外部データとの契約を書く

Stage 1 — 第4章 | dbt入門カリキュラム 推定学習時間:30〜40分 | 難易度:★★★☆☆


この章で学ぶこと

staging モデルの SQL は、多くの場合 {{ source('ソース名', 'テーブル名') }} から始まります。 これは「生 SQL で FROM app_db.orders と書く」のではなく、dbt プロジェクトの外にある表 を YAML で宣言してから参照する、という作法です。

この章では、まず source 定義(なぜ YAML か、ref() との違い、description に何を書くか)を整理します。 最後に、DS Playground の dbt プロジェクトが どういう方針で source を書いているか を短く見ます。

この章を終えると、こんなことができるようになります:

  • sources: YAML が 入力契約 である理由を説明できる
  • source()ref()使い分け られる
  • source の descriptionテーブルの性質(最新状態か、イベント履歴か)を書く意味を説明できる
  • 分析用 DB 接続を 読み取り専用 にする理由を説明できる

source() とは何か

dbt プロジェクトのモデルは、大きく 2 種類の入力 を持ちます。

  1. プロジェクト外の表 … アプリ DB、SaaS、ログ基盤など、dbt が作っていない表
  2. プロジェクト内の他モデル … すでに dbt が定義した staging / intermediate / marts

前者は source()、後者は ref() で参照します。

-- プロジェクト外(アプリ DB 等)
          select *
          from {{ source('app', 'orders') }}

          -- プロジェクト内(dbt モデル)
          select *
          from {{ ref('stg_orders') }}
          

source() を使うと、「この Transform はどの外部表から始まるか」 がコードと YAML の両方に残ります。 個人の BI クエリのように FROM 句に生の表名を直書きすると、入力の一覧や意味がプロジェクト外に散らばりやすくなります。

sources は アプリ DB が正本(SSOT) であり、dbt はその 読み取り側 という関係もここで固定されます。 データマネジメント入門の SSOT で学んだ「正本は一箇所」を、Transform の入口で実装している、と考えるとよいです。


sources YAML の書き方

source は _sources.yml のような YAML に宣言します。構造はシンプルです。

version: 2

          sources:
            - name: app          # source() の第 1 引数
              description: "本番アプリ DB の public スキーマ"
              database: analytics_raw
              schema: public
              tables:
                - name: orders
                  description: "注文ヘッダ。1 行 = 1 注文。"
                - name: order_events
                  description: "注文に関するイベント履歴。append-only。"
          
フィールド 意味
name source('app', ...)'app' 部分
database / schema 接続先の論理位置(環境ごとに切り替えることも多い)
tables[].name source(..., 'orders') の第 2 引数
tables[].description その表が何を表すか(後述)

接続パスワードや API キーは YAML に書きません。profiles.yml や CI の環境変数側に置き、repo には秘密を載せないのが通常です。


source() と ref() — lineage の入口

flowchart LR subgraph external["プロジェクト外(sources)"] RAW1[orders] RAW2[users] end subgraph dbt["dbt モデル"] STG[stg_orders] INT[int_orders_enriched] MART[fct_daily_orders] end RAW1 --> STG STG --> INT INT --> MART RAW2 -.-> INT
  • sources ノード … アプリ DB など dbt の外
  • model ノードref() でつながる dbt の内側

dbt docs の lineage では、この境界がはっきり見えます。 「ダッシュボードの数字はどの生表に遡るか」を説明するとき、sources が起点 になります。

staging では source()、intermediate / marts では基本的に ref() だけ、という 層ごとの約束 がよく使われます。 staging で ref() だけにすると、外部入力が見えにくくなります。逆に marts で source() を直叩きすると、依存がバラけます。


description に書くべきこと

source YAML の description は、飾りではなく 設計メモ です。 特に次の区別は、下流の KPI 定義に直結します。

最新状態(current-state)の表 … 同じキーの行が更新され、今の状態 が 1 行に載る。
イベント履歴(event log)の表 … 行が append され、いつ何が起きたか が残る。

この違いを source 段階で書いておくと、「この KPI は最新正答率か、初回正解率か」のような 取り違え を防げます。 staging が薄い設計ほど、ソースの意味 を YAML に残す価値が大きいです。

列名のリネームや型変換は staging SQL の仕事ですが、「この表は履歴か、スナップショットか」は source の description に書く、という分担が一般的です。


分析接続は読み取り専用に

dbt は Transform の結果を 分析用スキーマ(DS Playground では analytics)に build します。 一方、アプリ DB(OLTP)の表は SELECT だけ するのが原則です。

分析パイプラインにアプリと同じ 強権限(全表書き込み・RLS バイパスなど)を渡すと、Transform のバグや設定ミスが 本番データを壊す リスクにつながります。 そのため、dbt 用 DB ユーザーは 読み取り専用 にし、書き込み先を分析専用スキーマに限定する、という構成が一般的です。

アプリ ──書込──> OLTP 表(正本)
                              ^
                              | SELECT only
          dbt ────────────────┴──> 分析用 schema(dbt が CREATE)
          

データマネジメント入門の権限 で学んだ 最小権限 と同じ発想です。


DS Playground ではどうしているか

DS Playground の dbt プロジェクトは、Supabase の public スキーマ上のアプリ表を source('supabase', ...) で読みます。 YAML 側では name: supabase と宣言し、staging モデル stg_supabase__* がそれぞれ 1 source 表に対応します。

方針の要点だけ挙げます(全表の一覧は YAML 正本に任せ、ここでは覚えなくてよいです)。

  • アプリ DB が正本、dbt は read-only で読む
  • 加工結果は analytics スキーマに build する
  • source の description に、表が 最新状態かイベント履歴か を書く
  • 認証用の auth.users 等は analytics から直接読まず、分析に必要な同意・行動データ 経由で母集団を定義する

staging SQL の典型形は次のとおりです。

select
            user_id,
            consent_type,
            captured_at,
            cast(captured_at as date) as captured_date
          from {{ source('supabase', 'consents') }}
          where user_id is not null
          

consents のような 同意履歴 を会員数の proxy に使う、といった 定義の選択 は Stage 3 以降で詳しく読みます。 この章で押さえるのは、「外部表は source で宣言し、staging はそこから始める」という 構造 です。


体系コラム:カリキュラム上の位置づけ

項目 内容
Stage / 章 Stage 1 — 第4章
今回の論点 入力契約(sources)と read-only 接続
前章との接続 dbt project 構成
次章への伏線 staging:ソース意味を残す薄い変換

まとめ

sources は FROM 句に書く生の表名ではなく、外部データへの読み取り契約とメタデータ です。 source() で入口を固定し、下流は ref() でつなぐ——この境界が、dbt プロジェクトの最初の設計判断のひとつです。


関連教材


確認問題

問題 1

from {{ source('app', 'orders') }}from {{ ref('stg_orders') }} の違いとして 最も適切 なのはどれですか。

A. どちらも同じで、好みで置き換え可能
B. source() は dbt 外部 の宣言済み表、ref() は dbt 内部 モデルへの依存
C. source() は marts 専用、ref() は staging 専用
D. ref() だけが lineage に現れる

正解: B

解説: sources はプロジェクト外の入力、ref はプロジェクト内の依存です。staging は通常 source() を読み、下流は ref('stg_...') を読みます。


問題 2

分析用 dbt 接続を 読み取り専用(SELECT のみ) にする主な理由はどれですか。

A. dbt が INSERT をサポートしないから
B. Transform のミスでも OLTP の正本表を UPDATE/DELETE しないため
C. BI ツールが書き込みを禁止しているから
D. YAML に書けないから

正解: B

解説: 書き込み先は分析用スキーマに限定し、OLTP は読むだけ、という分離が一般的です。


問題 3

source YAML の description「append-only のイベント履歴」 と書く主な理由はどれですか。

A. SQL を短くするため
B. 下流で「最新状態」と「履歴」を取り違えないため
C. BI ツールの表示色を変えるため
D. seed ファイルの行数を減らすため

正解: B

解説: テーブルの性質は KPI 定義に効きます。イベント履歴と最新状態表を source 段階で区別しておくと、下流の staging 設計がぶれにくくなります。


用語メモ(この章)

用語 意味(この章での使い方)
source dbt 外部の生データ表(YAML で宣言)
source() 外部表を参照する dbt マクロ
ref() プロジェクト内の他モデルを参照する dbt マクロ
read-only OLTP 表は SELECT のみ。書き込みは分析用 schema へ