セマンティックレイヤー入門 ― 指標の定義を一本化する
マートを作っても、KPIの計算をBI・スプレッドシート・Reverse ETLでそれぞれ書くと、また定義がぶれます。セマンティックレイヤー(dbt Semantic Layer / MetricFlow等)で指標の定義をdbtに一元化し、どのツールからも同じ定義で取り出す発想を概観します。実験連載の指標設計、活性化連載の供給と地続きの発展回です。
by Akisame
マートまで整えたのに、なぜKPIの数字がBIとスプレッドシートとReverse ETLでまた割れるのか。原因は、指標の「集計ロジック」が各ツールに散らばっているからです。答えはセマンティックレイヤー――集計の定義をBI層から引き上げ、変換層(dbt)に一度だけ書いて、どのツールからも同じ定義で取り出します。この記事では、マートの先で定義がぶれる構造、セマンティックレイヤーの考え方(指標をdbtで定義する)、同一定義を下流へ供給する発想、そして指標設計との地続きを、過去の受託案件をもとに設計した架空のD2C「SOLNA」で概観します。
棲み分けを先に置きます。本連載は「データが入った後(ローデータ → マート)」を整える側で、データが生まれる前(収集・同意・識別・送信)は計測設計の連載(なぜ計測は静かに壊れるのか ― 計測設計という土台)の領域でした。前回(第7回)でマートを系譜と運用に乗せ、整える層は一段落しています。本回はその発展で、第5回で固めた「実体の単一定義(同じ顧客とは何か)」の一段上――「集計の単一定義(売上やCACをどう数えるか)」を扱います。SOLNA は連載共通の題材(D2Cスキンケアの定期購入モデル)で、以下の数値はすべて説明用のイメージ、または匿名化した実在案件のレンジ表記であり、特定企業の実測値ではありません。
マートの先で再び起きる「定義のぶれ」
第5回のマートは、「実体の定義」を一元化しました。customers の一行が指す顧客は誰か、orders の amount が何を意味するか――これは全社で一つになりました。しかし、KPIはマートそのものではありません。KPIはマートの上に乗る集計です。「売上」は orders.amount の合計ですが、その合計をどこで書くかが問題になります。
集計式の置き場は、放っておくと再び散らばります。BIツールの計算フィールド、経営会議用スプレッドシートの SUMIFS、Reverse ETL の変換クエリ、そして誰かのその場しのぎのSQL。マートは同じでも、その上の集計が四か所に別々に書かれていれば、第0回で見た「秘伝のタレ」が、今度はマートの上で再発します。
ぶれの原因は、たいてい三つに集約されます。第一に日付の境界――売上を注文日で数えるか、確定(出荷・入金)日で数えるか。第二に除外条件――返品・キャンセル・社内テスト購入を引くか含むか。第三に分母の窓――「アクティブ顧客」を直近30日とするか90日とするか。どれも「手法」の差ではなく、集計定義の差にすぎません。
一つ地に着けておきます。匿名化した実在のB2B案件(数値はレンジで丸めています)では、同一の月次KPIを三つの出口――経営ダッシュボード・広告レポート・手元スプレッドシート――で並べると、出口間で ±10〜20% ほどずれていました。原因はモデルの不一致ではなく、上記の集計定義の差でした。定義を一本化して全出口がそれを引くようにした後、出口間の差は丸め誤差(おおむね1%未満)に収束しました。
セマンティックレイヤーの考え方(指標をdbtで定義する)
セマンティックレイヤーの発想は単純です。集計の定義(指標)を、BI層から引き上げて変換層(dbt)に置きます。マートで「実体」を一度だけ定義したのと同じことを、「集計」に対しても行います。一度書けば、どのツールも同じ定義を引くしかなくなります。
dbtでは、これを二段で書きます。**メジャー(measure)**は sum や count といった集計の素材で、セマンティックモデル(マートに薄く乗せるメタ定義)の中に置きます。**メトリクス(metric)**は事業の言葉での定義で、メジャーの上に一度だけ書きます。エンドユーザーが触るのはメトリクスのほうです。
# セマンティックモデル: マート(第5回)の上に薄く乗せる。実体の確定はmartsで済んでいる。
# 注: 記法・キー名はバージョンで変わる(MetricFlow系)。正確な仕様は公式docsへ。
semantic_models:
- name: orders
model: ref('fct_orders') # 第5回で作ったマートを指す
entities:
- name: customer
type: foreign
expr: customer_id
dimensions:
- name: order_date
type: time
type_params: { time_granularity: day }
expr: order_at
measures:
- name: revenue_amount # 集計の「素材」(直接は引かせない)
agg: sum
expr: amount
- name: order_count
agg: count
expr: order_id
# メトリクス: 事業の言葉で、一度だけ定義する。
metrics:
- name: revenue
type: simple
type_params: { measure: revenue_amount }
- name: orders
type: simple
type_params: { measure: order_count }
- name: true_cac # 真のCAC = 出稿 / 新規顧客(第5回の素地を集計で確定)
type: ratio
type_params:
numerator: ad_spend # fct_ad_spend 側のmeasure
denominator: new_customers # customers 側のmeasure(新規のcount distinct)ここで注意が必要です。dbtのモデルはスキーマでスコープされます(別フォルダの同名 orders は別物として共存できる)が、セマンティックレイヤーの名前はプロジェクト全体で単一のネームスペースを共有します。エンティティ・ディメンション・メジャー・メトリクスのどれもが一つのネームスペースに登録されるので、ドメインをまたいで revenue を二度定義すると衝突します。実務ではドメイン接頭辞(d2c_revenue 等)を規約にして、命名規約をREADMEに残しておくのが安全です。第2回で staging に命名規約を置いたのと同じ規律を、ここでも繰り返すことになります。
これは新発明ではない ― 既にある考え方の言い換え
セマンティックレイヤーは、流行語として新しいだけで、思想は新しくありません。「集計を一度だけ定義し、複数の出口に同じ数字を渡す」という発想は、OLAPのセマンティックモデル(キューブの measure / dimension)に遡る数十年来のものです。それを近年のBIに持ち込んだのが LookML(モデリング層をコードで書くが、BIツールに結合していた)で、そこから定義をBIツールから切り離す動き――「ヘッドレスBI」「メトリクスレイヤー」――が出てきました。
つまり本質(集計を一度だけ定義する)は数十年変わっていません。本当に新しいのは一点、BIツールから切り離し、変換層(marts)の隣でversion管理するという デカップリング だけです。dbtのセマンティックレイヤーは MetricFlow を実行エンジンに持ち(Transform社の技術を取り込んだもの)、定義は marts と同じリポジトリでPRレビューに乗ります。第5回で marts の系譜が自動で立ったのと同じく、メトリクスもコードとして系譜の中に置かれます。新刊や新ツールに飛びつくより、「これは要するに OLAP の measure を、BIから剥がして git に置いただけだ」と本質で掴むほうが、導入判断を誤りにくくなります。
なお、同種の機能は dbt 以外にも複数あります(Cube のようなヘッドレスBI、DWH側の Snowflake Semantic Views / Databricks Metric Views 等)。ベンダー中立の相互運用標準(Open Semantic Interchange 等)も動き始めていますが、現時点では発展途上です。どれを選ぶかは既存スタック次第で、本連載の主題(整える層の設計)からは外れるため、ツール選定の詳細はdocsと各社比較に譲ります。
どのツールからも同じ定義で取り出す
定義を一本化しても、各ツールがそこを引かなければ意味がありません。セマンティックレイヤーは消費インターフェース(JDBC・GraphQL・RESTのAPI、CLI、BI統合)を持ち、BIもスプレッドシートも Reverse ETL も、テーブルを直接叩く代わりにメトリクスを引きます。
-- どのツールも、テーブルを直接叩かず「一つの定義」を引く。
-- (セマンティックレイヤーのSQLインターフェース。記法はバージョン依存=docs参照)
select
metric_time__month,
channel,
true_cac -- BIもスプレッドシートもReverse ETLも、同じ true_cac を引く
from {{ semantic_layer.query(
metrics=['true_cac'],
group_by=['metric_time__month', 'channel']
) }}CLIなら mf query --metrics true_cac --group-by metric_time__month,channel のように引きます。要点は記法ではなく、true_cac の計算式がどこにも再掲されていないことです。媒体ごとの出稿(ad_spend)を新規顧客(customers)で割る、という定義はメトリクスの一か所にしかありません。月次で見ようが媒体別で見ようが、引く側は次元(dimension)を指定するだけで、集計ロジックを書き直しません。前節のぶれ三因子(日付境界・除外条件・分母の窓)は、定義の中で一度だけ決着しているので、出口で再発しません。
活性化連載との接続もここで効きます。同連載のReverse ETL とモデル駆動オーディエンスは、「マート定義=オーディエンス」という発想でした。これにメトリクスの同一供給が乗ると、たとえば「LTV上位セグメント」を作るときの LTV が、ダッシュボードで見ている LTV と完全に一致します。ループを閉じた先の効果検証で、分子(成果)と分母(投下)が全出口で同じ定義になる――広告へ送るオーディエンスと、後で効果を測る指標が、同じ true_cac を共有する状態です。整える層が「動かす」と「測る」の両方に同じ物差しを渡すことになります。
指標設計との地続き(北極星指標・ガードレール)
ここで線を引いておきます。セマンティックレイヤーは「定義の置き場」であって、「何を北極星に据え、何をガードレールで見張るか」という選び方ではありません。後者は指標設計の主題です。両者は地続きで、役割が違います。指標設計で「主指標を一つ・ガードレールを数個・代理指標を一つ」と決め、それを走らせる前に固定します。その固定した定義を、セマンティックレイヤーが全ツールへ渡します。事前登録した指標が、文字どおりversion管理された単一の定義になる、という関係です。指標を何にするかの設計はメトリクス設計(北極星・ガードレール)に譲ります。
導入の損益分岐も率直に書きます。セマンティックレイヤーは無料の万能薬ではありません。落とし穴は三つあります。
第一に、スコープの代償。メトリクスとして定義したものしか引けません。モデルしていない問いには答えられず、新しい問いが出るたびにモデリングの手間がかかります。これは弱点というより設計思想で、「自由に何でも集計できる」ことと「数字が常に一致する」ことはトレードオフにあります。
第二に、ネームスペースの運用。前述のとおり全体で単一ネームスペースなので、ドメイン接頭辞の規約を最初に決めておかないと、規模が増えた時に衝突で詰まります。
第三に、コストと適用条件。エンジン(MetricFlow)自体はオープンですが、配信APIや一部機能はマネージドの有料層にあることが多いです。だから導入の発動条件は「データが多いから」ではなく、同一のメトリクスが複数の下流(BI+スプレッドシート+Reverse ETL)で消費されているかです。出口が単一のBIだけなら、セマンティックレイヤーは過剰になりやすく、BIツール内のモデリングで足ります。出口が増え、同じKPIが別々に書かれ始めた瞬間が、引き上げどきになります。
そもそも「整える層/その上のセマンティックレイヤーに投資すべきか」という決裁判断は、コードのないデータ基盤に投資すべきかに整理してあります。実装者は本連載で「どう一本化するか」を、決裁者は基幹記事で「いつ投資するか」を見てください。
整える層の到達点
連載をここで畳みます。第0回で「秘伝のタレSQL」がなぜ生まれるかを見ました。第1〜2回で3層とstaging、第3回でテスト、第4回でintermediate、第5回で marts = SOLNAスキーマ(実体の単一定義)を組み、第6回で incremental / snapshot により「過去の状態」を保ち、第7回で系譜と運用に乗せました。そして本回で、その上に乗る集計の単一定義を置きました。
整える層の到達点は、二層の「単一の真実」だと言えます。marts が実体の真実(同じ顧客・同じ注文とは何か)を、セマンティックレイヤーが集計の真実(売上・CAC・アクティブをどう数えるか)を持ちます。この二つが揃って初めて、下流の予測(Kaggle連載)・因果(因果連載)・活性化(活性化連載)が、同じ地面の上に立ちます。整える層は地味で売上に直結しませんが、その上のすべての分析の信頼性は、この二層の有無で決まります。
章末チェックリスト
- マートを整えても集計定義が散らばればKPIが再びぶれる、という構造を説明できる
- ぶれの三因子(日付境界・除外条件・分母の窓)を自社のKPIで点検したか
- メジャーとメトリクスの違い、定義をBI層から変換層へ引き上げる意味を言えるか
- 同一メトリクスをBI・スプレッドシート・Reverse ETLが同じ定義で引く状態になっているか
- セマンティックレイヤーは「定義の置き場」、指標設計は「選び方」、と役割を区別できるか
- 導入の発動条件(同一指標が複数の下流で消費されているか)と代償(スコープ・ネームスペース・コスト)を天秤にかけたか
指標を何にするか――北極星とガードレールの設計はメトリクス設計(北極星・ガードレール)へ。整えた定義を実際に動かす供給はReverse ETL とモデル駆動オーディエンスへ。土台の上で「何を測り、何を動かすか」を考える段階は記述・予測編へ。整える層が、定義の単一の真実として、全体を静かに支えます。