青の統計学-DS Playground-

snapshots と exposures:履歴化と下流利用者管理

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


この章で学ぶこと

mart は 現時点の SSOT ですが、運用には 「いつ変わったか」「誰がどの表を使うか」 も必要です。

まず dbt snapshot と exposure の作法を整理し、続けて DS Playground の snapshot_user_learning_preferencesmodels/exposures.yml を読み解きます。

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

  • timestamp strategy snapshot の config を読める
  • snapshot が mart に未接続でも価値がある理由を説明できる
  • exposure が メタデータとリネージ をどう伸ばすか説明できる
  • 2 つの Metabase exposure の depends_on 差を説明できる

snapshot とは何か

ソースが current-state(最新状態だけを保持)のとき、mart は build 時点のスナップショットしか見えません。 ユーザー属性が変わっても、過去の mart 行は 遡及更新されません

将来「月次で構成がどう変わったか」を見るには 履歴テーブル が必要です。

方式 特徴
アプリ側 event 履歴 正攻法。アプリ改修が必要
dbt snapshot ソースが current-state のまま履歴を後付け

dbt snapshot は SCD(Slowly Changing Dimension) を warehouse 上に作る機能です。 strategy='timestamp' では、変更検知列(例: updated_at)の変化で新しい履歴行を追加します。

flowchart LR SRC["current-state
ソース / staging"] SNAP["snapshot
(履歴テーブル)"] MART["current-state mart
(現時点の集計)"] FUTURE["将来の推移 mart
(任意)"] SRC --> SNAP SNAP -.-> FUTURE SRC --> MART

データマネジメント入門 の「保存期間と改訂履歴」が snapshot に相当します。


exposure とは何か

dbt の exposure は、プロジェクト外の 利用面(ダッシュボード、Notebook、逆 ETL)を lineage グラフに載せる機能です。

dbt docs generate の lineage 上で mart → exposure の矢印が見えます。

効果 説明
影響範囲分析 mart 変更時に どのダッシュボードが壊れるか
オーナーシップ owner.email で問い合わせ先
ドキュメント docs artifact で利用者向け索引
SSOT 「この会議はこの exposure の mart セットを見る」と合意

Harness Engineering と DM の「外部利用面のハーネス」に近い考え方です。


snapshot 運用上の注意

  1. snapshot も build 対象 — 日次 workflow で増える
  2. PII — ユーザー ID を含む場合は内部 schema のみ
  3. mart との二重 SSOT — 現在値は mart、履歴は snapshot と 役割分担 を YAML に書く
  4. full-refresh — snapshot 再構築は慎重に(履歴消失リスク)

snapshot と current-state mart は 役割が異なります。 snapshot は履歴 as-of 用、mart は build 時点の集計用——混同しないことが重要です。


snapshot_user_learning_preferences

fct_learning_goal_share現在の primary_goal だけを見ます。 ユーザーが goal を変更しても、過去の構成比 mart は遡及更新されません。

教学例として、学習目的の履歴化 snapshot を置いています。

{% snapshot snapshot_user_learning_preferences %}

          {{
            config(
              target_schema=target.schema,
              strategy='timestamp',
              unique_key='user_id',
              updated_at='updated_at',
              invalidate_hard_deletes=True
            )
          }}

          select
            user_id,
            primary_goal,
            preference_source,
            created_at,
            updated_at
          from {{ ref('stg_supabase__user_learning_preferences') }}

          {% endsnapshot %}
          

config の読み方

設定 意味
strategy='timestamp' updated_at 変化で新 SCD 行
unique_key='user_id' 1 ユーザー 1 現行行の追跡
invalidate_hard_deletes=True ソースから消えた行を snapshot 上で無効化
flowchart LR STG["stg_supabase__user_learning_preferences
(current)"] --> SNAP["snapshot_user_learning_preferences
(history)"] SNAP -.->|将来| MART["goal 推移 mart(未実装)"] STG --> FCT["fct_learning_goal_share
(現在構成のみ)"]

snapshot を将来 mart に接続するか、教学例のままにするかはプロジェクト方針で決めます。 mart に未接続でも、履歴テーブルとしての価値(将来の as-of 分析の土台)はあります。


exposures.yml

Metabase ダッシュボード想定ごとに どの mart を読むか を宣言しています。

exposures:
            - name: metabase_product_health_dashboard
              type: dashboard
              depends_on:
                - ref('fct_membership_daily')
                - ref('fct_active_users_daily')
                # ...
              owner:
                name: "BlueBayes / DS Playground"
                email: "analytics@bluebayes.jp"
          

2 つの dashboard exposure

metabase_product_health_dashboard — 有料化前プロダクトヘルス

依存 mart(例) ファミリー
fct_membership_daily, fct_membership_conversion_daily Membership / Monetization
fct_active_users_daily, fct_active_users_daily_by_member_status Activity
fct_activity_events_daily_by_type Activity mix
fct_active_users_period_summary DAU/WAU/MAU
fct_skill_check_daily Skill check
fct_user_engagement_distribution_current Engagement

metabase_pre_monetization_research_dashboard — 学習目的・調査・教材品質

依存 mart ファミリー
fct_learning_goal_share, fct_member_survey_option_share Demand
fct_problem_quality, fct_problem_category_quality Content quality
flowchart TB subgraph product_health["metabase_product_health_dashboard"] PH1["membership marts"] PH2["activity marts"] PH3["engagement distribution"] end subgraph research["metabase_pre_monetization_research_dashboard"] R1["survey marts"] R2["content quality marts"] end PH1 --> MB1["Metabase 内部"] PH2 --> MB1 PH3 --> MB1 R1 --> MB2["Metabase 内部"] R2 --> MB2

exposure の maturity は medium です。 ダッシュボード URL は作成後に YAML へ追記する運用です。


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

項目 内容
Stage / 章 Stage 5 — 第2章
今回の論点 SCD snapshot、dashboard lineage、2 exposure の分割
前章との接続 safe_ratio マクロ
次章への伏線 CI / docs / Capstone

まとめ

dbt は warehouse 内の transform だけでなく、履歴(snapshot)と利用面(exposure) までモデルグラフに載せられます。

DS Playground では、current-state mart と snapshot の役割分担、ヘルス vs リサーチの exposure 分割——という運用設計がコード上で可視化されています。


関連教材


確認問題

問題 1

strategy='timestamp' の snapshot で、新しい snapshot 行が作られる典型トリガーはどれですか。

A. 毎日 0 時に無条件
B. ソースの updated_at(等の変更検知列)が変わったとき
C. BI ツールが更新されたとき
D. seed が変わったとき

正解: B


問題 2

exposure を _exposures.yml に定義する 主な目的 として最も近いのはどれですか。

A. SQL を短くする
B. mart 変更の影響がダッシュボード等に及ぶことを lineage で可視化する
C. OLTP の RLS を設定する
D. incremental lookback を決める

正解: B


問題 3

snapshot と current-state mart の関係について 正しい 説明はどれですか。

A. snapshot は mart の代替で、current-state mart は不要
B. snapshot は履歴 as-of 用、current-state mart は build 時点のスナップショット用
C. どちらも BI から直接 source() を読む
D. snapshot は seed の別名

正解: B


用語メモ(この章)

用語 意味(この章での使い方)
snapshot current-state ソースから SCD 履歴テーブルを作る dbt 機能
timestamp strategy 変更検知列の変化で新履歴行を追加する方式
current-state build 時点の最新状態。過去 as-of 不可
exposure ダッシュボード等の利用面を lineage に載せる宣言
SCD 属性の変化を履歴として保持する次元設計