「先月の売上は?」と聞いて、部署ごとに違う数字が返ってくる。データ基盤を運用していると必ず通る問題です。原因はデータの品質ではなく、「売上」の定義が置かれている場所が散らばっていることにあります。この記事では、データ層と を分けるという考え方を、手法・ツールの比較とdbt での具体例とともに整理します。
dbt での実装手順は dbt ハンドブック EP.14 に独立した記事があります。この記事はその手前、なぜ分けるのか・どの方式を選ぶのか・どこに何を置くのかという設計と選定の話です。指標そのものの設計は 指標設計の教科書 を参照してください。
1. なぜ数字が食い違うのか
食い違いの原因を辿ると、ほぼ必ず同じ計算が複数の場所に書かれていることに行き着きます。しかも厄介なのは、どれも間違っていないことです。返品を含むか、税を含むか、キャンセル分をいつ引くか。それぞれの部署の文脈では正しく、突き合わせた瞬間に破綻します。
| 定義が置かれる場所 | 起きること |
|---|---|
| BI ツールの計算フィールド | BI を増やすと再実装され、微妙にずれる |
| 各自の SQL / スプレッドシート | 書いた人しか正しさを判定できない |
| アプリのコード | 画面の数字とレポートの数字が合わない |
| マートのテーブル | 粒度ごとに増殖し、どれが正か分からなくなる |
どれも「定義」ではなく「定義の実装」が置かれている点が共通しています。実装が増えるほど、真実は分散します。層を分けるとは、実装を増やさずに定義を1つ持つための構造化です。
2. 層をどう切るか
実務でうまく回っている構成は、おおむね次の3層です。どこに何を置くかの線引きが曖昧なまま製品を入れても、結局は散らばります。
| 層 | 持つもの | 持たないもの | 変更の理由 |
|---|---|---|---|
| データ層 | 整形済みの事実(テーブル)、結合、粒度の統一 | 指標の定義 | ソースの仕様変更 |
| セマンティック層 | 指標の定義、切り口、時間の扱い、アクセス制御 | 描画、レイアウト | 業務ルールの変更 |
| 表現層(BI・アプリ) | 見せ方、フィルタの初期値、レイアウト | 計算ロジック | 見せ方の要望 |
「変更の理由」の列が判断の軸です。ソースの仕様が変わったときに触る場所と、業務ルールが変わったときに触る場所と、見せ方の要望で触る場所は、別々であるべきです。同じファイルを3つの理由で触っているなら、層が混ざっています。
「この計算は、BI を別の製品に乗り換えても同じであるべきか」。イエスならセマンティック層です。「この見せ方は、この画面固有か」。イエスなら表現層。この2問でほとんど分類できます。
3. 方式の比較
セマンティック層の実現方法は 5 つに大別できます。製品を選ぶ前に方式を選ぶのが順序です。
| 方式 | 代表例 | メリット | デメリット | 向いている状況 |
|---|---|---|---|---|
| BI 内蔵型 | など | BI との統合が滑らか。学習コストが低い | 定義が BI 製品に縛られる。他の出口から使えない | BI が1つに固定されている |
| 変換ツール統合型 | dbt の | モデルと同じリポジトリで管理。レビュー・CI が既存の流れに乗る | dbt を使っていることが前提 | 既に dbt が中核にある |
| 型 | 独立した専用製品 | BI 非依存。API から複数の出口に配れる | 構成要素が増える。運用対象が1つ増える | 出口が複数ある |
| 自前ビュー / マート型 | DWH のビュー | 追加の製品が不要。すぐ始められる | 粒度ごとに増殖する。切り口の追加が重い | 小規模・出口が少ない |
| やらない(各自定義) | — | 初速が最も速い | 規模とともに必ず破綻する | 立ち上げ直後のみ |
最初から3番目を選ぶ必要はありません。多くの現場にとって現実的なのは、4 → 2 → 3 という順の成長です。ビューで始め、dbt が中核になった段階で定義を寄せ、出口が増えたら独立させる。最初から重い構成を入れると、指標が固まる前に運用が重くなります。
4. dbt での具体例
dbt を使っている場合、モデルと同じリポジトリで指標を定義できるのが最大の利点です。SQL のレビューと同じ流れで、指標定義の変更もレビューできます。まず「分ける前」を見ます。
-- BI の計算フィールドや、担当者ごとの SQL に、この式が繰り返し書かれるselect date_trunc('month', ordered_at) as month, store_id, -- ここが「売上の定義」。キャンセルと返品の扱いがここに埋まっている sum(case when status != 'canceled' then amount - refund_amount else 0 end) as revenuefrom {{ ref('fct_orders') }}group by 1, 2
-- 問題: 粒度を変えたい(日次にしたい、商品別にしたい)たびに-- 同じ式をコピーした別のクエリが増えていく定義(何を売上と呼ぶか)と、粒度(どの軸で集計するか)が同じ SQL に同居しているのが問題です。粒度を変えたくなるたびに定義がコピーされます。分けると次の形になります。
semantic_models: - name: orders model: ref('fct_orders') defaults: agg_time_dimension: ordered_at
entities: - name: order type: primary expr: order_id - name: store type: foreign expr: store_id
dimensions: - name: ordered_at type: time type_params: time_granularity: day - name: channel type: categorical
measures: # 「売上」の計算はここ 1 箇所だけに書く - name: net_revenue expr: case when status != 'canceled' then amount - refund_amount else 0 end agg: sum
metrics: - name: revenue label: 売上 description: キャンセルを除き、返品額を差し引いた確定売上 type: simple type_params: measure: net_revenue粒度がどこにも書かれていない点が要点です。月次でも日次でも、店舗別でもチャネル別でも、呼び出し側が切り口を指定すれば同じ定義から計算されます。粒度ごとのマートを作る必要がなくなり、同時に定義の重複も消えます。
上の例で `description` にキャンセルと返品の扱いを明記しているのが重要です。指標の食い違いは技術的な誤りより、「何を含むかの認識違い」で起きます。定義の隣に日本語の説明を必ず置いてください。この一行が、後の会議を何時間も短縮します。
5. 移行の順序
既にある環境に後付けする場合、全部を一度に移すのは失敗します。次の順序が現実的です。
- 1食い違っている指標を数える。まず現状を可視化する。ここで「思ったより少ない / 多い」が判明する
- 2最も揉める指標を1つだけ移す。売上や継続率など、会議で必ず話題になるもの
- 3新しい出口から先に使う。既存 BI の書き換えは後回しにし、新規のダッシュボードだけ新しい定義で作る
- 4古い実装を消す。ここまでやらないと二重管理が残り、むしろ状況が悪化します
移行で最も多い失敗は、新しい層を作ったが古い定義も残っている状態で止まることです。定義が2箇所になり、分ける前より悪くなります。1 指標ずつでよいので、必ず古い方を消すところまでを1セットにしてください。
6. 導入すべきかの判断
| 状況 | 判断 |
|---|---|
| BI が1つ、出口も1つ | 不要。BI 内で定義して構わない |
| 同じ指標を2箇所以上で計算している | 定義の集約を始める時期 |
| 会議で数字の食い違いが議題になる | 既に手遅れ気味。優先度を上げる |
| BI 以外の出口がある(アプリ・通知・外部提出) | 型を検討 |
| dbt が中核にある | 変換ツール統合型が最短 |
| 指標がまだ固まっていない | 待つ。定義が動く段階で層を固めない |
最後の行が見落とされがちです。プロダクトが立ち上がったばかりで指標そのものが週ごとに変わる段階では、層を固める投資は早すぎます。定義が安定してきた兆候が出てからで十分間に合います。
7. 落とし穴
- 古い定義を消さない: 二重管理になり、分ける前より悪化する
- 表現層に計算を残す: BI の計算フィールドが1つでも残ると、そこから再び分散が始まる
- description を書かない: 食い違いの主因は技術ではなく認識の差
- 指標が固まる前に層を固める: 変更のたびに層の改修が必要になり、開発が止まる
- 全指標を一度に移す: 検証が追いつかない。揉める指標から1つずつ
- アクセス制御を後回しにする: 誰がどの粒度まで見てよいかは層の設計に含まれる
- BI 製品に定義を縛る: 乗り換え時に全て書き直しになる。移植性は選定時に評価する
8. ふくふくの進め方
「部署ごとに数字が違う」というご相談では、まず食い違っている指標を数えるところから入ります。多くの場合、問題になっているのは全指標のうち数個で、そこだけ先に集約すれば会議は静かになります。全社的なセマンティック層の整備は、その効果を実感してからの方が合意も取りやすい、というのが実感です。
9. ここまでのまとめ
- 数字の食い違いは品質の問題ではなく、定義の実装が複数箇所にあるという構造の問題
- 層は データ層 / セマンティック層 / 表現層。「変更の理由」で切る
- 方式は5つ。製品より先に方式を選ぶ。多くの現場は 自前ビュー → dbt 統合 → ヘッドレス の順で育つ
- dbt なら指標定義をモデルと同じリポジトリで管理でき、粒度を定義から追い出せる
- `description` に「何を含むか」を書く。食い違いの主因は認識の差
- 移行は揉める指標1つから。そして古い実装を消すところまでが1セット
- 指標が固まっていない段階では層を固めない
セマンティック層は流行りの構成に見えて、やっていることは 「定義を1箇所に置く」 という基本の徹底です。だからこそ、製品を入れれば解決する類の話ではありません。dbt での実装は dbt ハンドブック EP.14、指標そのものの設計は 指標設計の教科書 EP.12 に譲ります。続編では、アクセス制御を含めた層の設計、移行時の二重管理を防ぐ運用、ヘッドレス構成の実例などを、読者リアクションに応じて随時追加していきます。
この記事の感想を教えてください
あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。