ストーリー
田
田中VPoE
データレイク、DWH、レイクハウス、ディメンショナルモデリング。ストレージからモデリングまで一通り学んだ。実際のシナリオでDWHを設計してもらう
あなた
Step 1のDataFlow社のシナリオの続きですか?
あ
田
田中VPoE
そうだ。DataFlow社のデータ基盤をゼロから設計する。ストレージ構成、テーブル設計、dbtモデル、クエリ最適化まで一貫した設計書を作ってくれ
あなた
Medallionアーキテクチャを使って、Bronze/Silver/Goldの各層を設計します
あ
田
田中VPoE
ビジネス要件を満たすディメンショナルモデルを設計してくれ。特に「アクティブユーザー」の定義を統一し、複数部門から信頼されるSingle Source of Truthを作ることが目標だ
ミッション概要
| 項目 | 内容 |
|---|
| 演習タイトル | データウェアハウスの設計 |
| 想定時間 | 90分 |
| 成果物 | DWH設計書(ストレージ設計 + ディメンショナルモデル + dbtモデル) |
| 対象企業 | DataFlow社(Step 1から継続) |
ビジネス要件
DataFlow社のビジネス要件:
1. KPI統一
- アクティブユーザー: 過去30日間に1回以上ログインしたユーザー
- チャーン率: 月初のアクティブユーザーのうち、月末に非アクティブになった割合
- MRR: 当月の有効サブスクリプション × 月額料金の合計
- NRR: (期首MRR + 拡大MRR - 縮小MRR - 解約MRR) / 期首MRR
2. 分析ユースケース
- 日次売上レポート(翌朝9時までに提供)
- 顧客セグメント別のLTV分析
- キャンペーン効果測定(配信→開封→クリック→コンバージョン)
- チャーン予測モデルの学習データ
3. パフォーマンス要件
- ダッシュボードのクエリ応答: 10秒以内
- 日次バッチの完了: 朝8時までに
- データ保持期間: 3年間
Mission 1: ストレージ構成の設計
要件
DataFlow社のデータレイクとDWHのストレージ構成を設計してください。
- データレイクのディレクトリ構造を設計する
- パーティショニング戦略を定義する
- ファイルフォーマットとライフサイクルポリシーを決定する
解答例
ディレクトリ構造
s3://dataflow-data-lake/
├── bronze/
│ ├── app_db/ # PostgreSQL CDC
│ │ ├── users/
│ │ ├── subscriptions/
│ │ ├── campaigns/
│ │ └── email_deliveries/
│ ├── event_logs/ # MongoDB
│ │ └── clickstream/
│ ├── salesforce/ # Fivetran
│ │ ├── accounts/
│ │ └── opportunities/
│ ├── hubspot/ # Fivetran
│ │ └── leads/
│ └── stripe/ # Fivetran
│ ├── invoices/
│ └── subscriptions/
├── silver/
│ ├── users/
│ ├── subscriptions/
│ ├── events/
│ ├── campaigns/
│ └── payments/
├── gold/
│ ├── dimensions/
│ │ ├── dim_customer/
│ │ ├── dim_date/
│ │ ├── dim_plan/
│ │ └── dim_campaign/
│ ├── facts/
│ │ ├── fact_subscription/
│ │ ├── fact_user_activity/
│ │ └── fact_campaign_performance/
│ └── marts/
│ ├── revenue_daily/
│ ├── customer_ltv/
│ └── churn_features/
└── _system/
├── data_quality/
└── audit_logs/
パーティショニング
| テーブル | パーティション | クラスタリング |
|---|
| fact_user_activity | activity_date (DATE) | customer_key |
| fact_subscription | effective_date (DATE) | customer_key, plan_key |
| fact_campaign_performance | send_date (DATE) | campaign_key |
フォーマット・ライフサイクル
| 層 | フォーマット | 0-90日 | 90-365日 | 1年以上 |
|---|
| Bronze | Parquet | Standard | Standard IA | Glacier IR |
| Silver | Parquet | Standard | Standard | Standard IA |
| Gold | Parquet | Standard | Standard | Standard |
Mission 2: ディメンショナルモデルの設計
要件
DataFlow社のビジネス要件を満たすスタースキーマを設計してください。
- ファクトテーブルを3つ以上設計する
- ディメンションテーブルを4つ以上設計する(コンフォームドディメンション含む)
- SCD Type 2を1つ以上のディメンションに適用する
- 「アクティブユーザー」「MRR」「チャーン率」を計算するために必要なモデルを設計する
解答例
ER図
┌─────────────┐
│ dim_date │
└──────┬──────┘
│
┌─────────────┐ ┌────┴────────────┐ ┌──────────────┐
│ dim_customer │──│ fact_subscription│──│ dim_plan │
│ (SCD Type 2)│ └────┬────────────┘ └──────────────┘
└──────┬──────┘ │
│ ┌────┴────────────────┐
├─────────│ fact_user_activity │
│ └─────────────────────┘
│
│ ┌────────────────────────┐ ┌──────────────┐
└─────────│ fact_campaign_perform. │──│ dim_campaign │
└────────────────────────┘ └──────────────┘
ファクトテーブル
| テーブル名 | 粒度 | メジャー |
|---|
| fact_subscription | 1行 = 1サブスクリプション期間 | mrr, arr, 契約日数 |
| fact_user_activity | 1行 = 1ユーザー × 1日 | login_count, feature_usage_count, session_duration_sec |
| fact_campaign_performance | 1行 = 1配信 × 1受信者 | is_delivered, is_opened, is_clicked, is_converted |
ディメンションテーブル
| テーブル名 | SCD | 主要属性 |
|---|
| dim_customer | Type 2 | customer_id, name, segment, industry, plan, created_at |
| dim_date | Type 0 | full_date, year, quarter, month, is_weekend, is_holiday |
| dim_plan | Type 1 | plan_name, monthly_price, annual_price, features |
| dim_campaign | Type 1 | campaign_name, channel, target_segment, start_date |
Mission 3: dbtモデルの設計
要件
「アクティブユーザー数」「MRR」「チャーン率」を計算するdbt Goldモデルを設計してください。
- SQLクエリを記述する
- dbt testsを定義する
- ドキュメント(description)を記述する
解答例
-- models/gold/marts/mart_monthly_metrics.sql
-- 月次KPIメトリクス
{{ config(
materialized='table',
partition_by={'field': 'metric_month', 'data_type': 'date'}
) }}
WITH active_users AS (
SELECT
DATE_TRUNC(activity_date, MONTH) AS metric_month,
COUNT(DISTINCT customer_key) AS active_user_count
FROM {{ ref('fact_user_activity') }}
WHERE login_count > 0
GROUP BY 1
),
mrr AS (
SELECT
DATE_TRUNC(effective_date, MONTH) AS metric_month,
SUM(mrr) AS total_mrr
FROM {{ ref('fact_subscription') }}
WHERE status = 'ACTIVE'
GROUP BY 1
),
churn AS (
SELECT
metric_month,
active_start,
active_end,
SAFE_DIVIDE(active_start - active_end, active_start) AS churn_rate
FROM (
SELECT
DATE_TRUNC(d.full_date, MONTH) AS metric_month,
COUNT(DISTINCT CASE
WHEN ua_start.login_count > 0 THEN ua_start.customer_key
END) AS active_start,
COUNT(DISTINCT CASE
WHEN ua_end.login_count > 0 THEN ua_end.customer_key
END) AS active_end
FROM {{ ref('dim_date') }} d
LEFT JOIN {{ ref('fact_user_activity') }} ua_start
ON ua_start.activity_date BETWEEN DATE_TRUNC(d.full_date, MONTH)
AND DATE_ADD(DATE_TRUNC(d.full_date, MONTH), INTERVAL 29 DAY)
LEFT JOIN {{ ref('fact_user_activity') }} ua_end
ON ua_end.activity_date BETWEEN DATE_SUB(LAST_DAY(d.full_date), INTERVAL 29 DAY)
AND LAST_DAY(d.full_date)
AND ua_end.customer_key = ua_start.customer_key
WHERE d.full_date = DATE_TRUNC(d.full_date, MONTH)
GROUP BY 1
)
)
SELECT
a.metric_month,
a.active_user_count,
m.total_mrr,
c.churn_rate
FROM active_users a
LEFT JOIN mrr m ON a.metric_month = m.metric_month
LEFT JOIN churn c ON a.metric_month = c.metric_month
dbt テスト定義
# models/gold/marts/schema.yml
models:
- name: mart_monthly_metrics
description: "月次KPIメトリクス。アクティブユーザー数、MRR、チャーン率を統合"
columns:
- name: metric_month
description: "メトリクスの対象月(月初日)"
tests:
- not_null
- unique
- name: active_user_count
description: "過去30日間に1回以上ログインしたユーザー数"
tests:
- not_null
- dbt_utils.expression_is_true:
expression: ">= 0"
- name: total_mrr
description: "月次経常収益(Monthly Recurring Revenue)"
tests:
- not_null
- dbt_utils.expression_is_true:
expression: ">= 0"
- name: churn_rate
description: "月次解約率"
tests:
- dbt_utils.accepted_range:
min_value: 0
max_value: 1
達成度チェック
| 観点 | 達成基準 |
|---|
| ストレージ設計 | Medallionアーキテクチャに基づくディレクトリ構造が設計されている |
| ディメンショナルモデル | ファクト3つ以上、ディメンション4つ以上、SCD Type 2が含まれている |
| dbtモデル | KPI計算SQLが記述され、テストとドキュメントがある |
| ビジネス要件の充足 | アクティブユーザー、MRR、チャーン率の定義が統一されている |
推定所要時間: 90分