dbt Semantic Layer で単一のセマンティックモデルで定義できる代表的なメトリクスタイプを試してみる
はじめに
dbt Semantic Layer では、YAML でメトリクスを定義することでビジネス指標を一元管理できます。
単一のセマンティックモデル上で定義できる代表的なメトリクスタイプ(Simple・Derived・Ratio・Cumulative)の定義方法と動作を確認した際の内容を記事としました。
dbt Semantic Layer のメトリクスタイプの概要
dbt Semantic Layer では、セマンティックモデルに対してメトリクスを YAML で定義します。メトリクスタイプによって集計のロジックや用途が異なり、目的に応じて使い分けることができます。
一部ですが、単一のセマンティックモデル上で定義できる代表的なメトリクスとして以下があります。
| メトリクスタイプ | 概要 |
|---|---|
| Simple | 単一カラムを1つの集計関数で集計する基本 |
| Derived | 既存のメトリクスを組み合わせた計算式を定義する |
| Ratio | 分子・分母を明示して比率を計算する |
| Cumulative | 時間軸に沿って値を累積集計する |
前提条件
検証環境
以下の環境を使用しています。
- dbt
- dbt Cloud
- dbt CLI:0.40.15(2026-03-02 ビルド)
- DWH:Snowflake
また、この記事では dbt Fusion エンジンおよび dbt platform Latest リリーストラックで利用可能な新しい YAML 記法(モデルの columns 配下にセマンティックモデル定義を記述する形式)を使用しています。
事前準備
検証には jaffle_shop の公式サンプルデータを使用します。以下のテーブルを事前に用意しておきました。
| ソース | テーブル | 説明 |
|---|---|---|
raw.jaffle_shop |
orders |
注文データ(1行=1注文) |
この環境については、以下の記事で用意したものをそのまま使用しています。
検証開始時点で、モデル(models/stg_orders.sql)の定義は以下のようになっていました。
注意点として、amount 列をこちらで追加しています。
select
id as order_id,
user_id as customer_id,
order_date,
status,
abs(hash(id)) % 9901 + 100 as amount -- ダミー金額(order_id ベースの決定論的な値、100〜10000)
from {{ source('jaffle_shop', 'orders') }}
また、YAML 定義は以下のようになっていました。
# models/stg_orders.yml
version: 2
models:
- name: stg_orders
semantic_model:
enabled: true
agg_time_dimension: order_date
columns:
- name: order_id
entity:
type: primary
name: orders
- name: customer_id
entity:
type: foreign
name: customer
- name: order_date
granularity: day
dimension:
type: time
- name: status
dimension:
type: categorical
metrics:
- name: order_count
type: simple
label: 注文数
agg: count
expr: 1
- name: distinct_customers
type: simple
label: ユニーク顧客数
agg: count_distinct
expr: customer_id
- name: total_amount
type: simple
label: 合計金額
agg: sum
expr: amount
- name: average_order_amount
type: simple
label: 平均注文金額
agg: average
expr: amount
その他注意点として、以降では特に明記しませんが、開発環境などで YAML 変更後はdbt parseを実行してからクエリする必要があります。
Simple メトリクス
概要
セマンティックモデル内の単一の列に対して直接的な集計を行うための基本的なメトリクスとなります。
シンプルメトリクスとして定義するには、メトリクス定義でtype: simpleと設定します。あわせて、agg:プロパティで具体的な集計方法を指定します。指定可能なオプションは以下の通りです。
| agg 種類 | 説明 |
|---|---|
count |
行数をカウント(expr: 1 で全行対象) |
count_distinct |
指定カラムの重複除去カウント |
sum |
合計値 |
average |
平均値 |
median |
中央値 |
min |
最小値 |
max |
最大値 |
percentile |
パーセンタイル値(percentile と percentile_type の追加指定が必須) |
sum_boolean |
boolean カラムの true 件数を合計 |
具体的な定義例は以下の通りです。
name, type, label(BI ツールなどに表示される表示名), agg は必須です。
また、対象とある列名はexprで指定します。ここで指定がない場合、デフォルトではメトリクス名がそのまま使用されます。
metrics:
- name: order_count
type: simple
label: 注文数
agg: count
expr: 1 # COUNT(1) と同等。全行を対象にする慣用表現
- name: distinct_customers
type: simple
label: ユニーク顧客数
agg: count_distinct
expr: customer_id # このカラムの重複除去カウント
- name: total_amount
type: simple
label: 合計金額
agg: sum
expr: amount
- name: average_order_amount
type: simple
label: 平均注文金額
agg: average
expr: amount
基本的な定義に対してクエリしてみます。
$ dbt sl query --metrics order_count,distinct_customers,total_amount,average_order_amount
+----------------------+--------------------+-------------+--------------+
| AVERAGE_ORDER_AMOUNT | DISTINCT_CUSTOMERS | ORDER_COUNT | TOTAL_AMOUNT |
+----------------------+--------------------+-------------+--------------+
| 4908.989899 | 62 | 99 | 485990 |
+----------------------+--------------------+-------------+--------------+
それぞれ以下の内容です。
order_count= 99(全注文数)distinct_customers= 62(ユニーク顧客数)total_amount= 485990(金額の合計)average_order_amount= 4908.99(金額の平均)
通常の SQL でも確認すると同様の結果になっていることがわかります。
$ SELECT
COUNT(1) AS order_count,
COUNT(DISTINCT customer_id) AS distinct_customers,
SUM(amount) AS total_amount,
AVG(amount) AS average_order_amount
FROM DBT_SL_DB.DBT_TYASUHARA.STG_ORDERS;
+-------------+--------------------+--------------+----------------------+
| ORDER_COUNT | DISTINCT_CUSTOMERS | TOTAL_AMOUNT | AVERAGE_ORDER_AMOUNT |
|-------------+--------------------+--------------+----------------------|
| 99 | 62 | 485990 | 4908.989899 |
+-------------+--------------------+--------------+----------------------
行レベルの計算式
exprプロパティでは、集計の対象となる列名を指定できますが、ここではカラム名だけでなく行レベルの計算式を直接記述できます。また、この場合は行単位で計算してから集計するという動作になります。
例として、以下のメトリクスを追加します。
- name: total_tax_amount
type: simple
label: 消費税額合計
agg: sum
expr: amount * 0.1 # 行ごとに amount * 0.1 を計算してから SUM する
この場合、生成される SQL は以下のようになります。
$ dbt sl query --metrics total_tax_amount --compile
SELECT
SUM(amount * 0.1) AS total_tax_amount
FROM dbt_sl_db.dbt_tyasuhara.stg_orders stg_orders_src_10000
LIMIT 100
フィルタ
また、メトリクス定義に絞り込み条件を固定することもできます。dbt コマンドでクエリ時に--whereを使用することもできますが、メトリクスと定義することで他のメトリクスからの利用も可能です。
- name: returned_order_count
type: simple
label: 返品注文数
agg: count
expr: 1
filter: "{{ Dimension('orders__status') }} = 'returned'"
# {{ Dimension('entity名__dimension名') }} の形式でディメンションを参照する
生成される SQL は以下のようになります。WHERE 句として集計前に適用されます。
$ dbt sl query --metrics returned_order_count --compile
SELECT
SUM(returned_order_count) AS returned_order_count
FROM (
SELECT
status AS orders__status
, 1 AS returned_order_count
FROM dbt_sl_db.dbt_tyasuhara.stg_orders stg_orders_src_10000
) subq_2
WHERE orders__status = 'returned'
LIMIT 100
percentile
percentile もシンプルメトリクスで使用できる集計関数の一つとして用意されています。
単一の列に対して、特定のパーセンタイル値を計算したい場合に使用されます。
agg: percentileを指定することでパーセンタイルでの集計となり、追加で以下の2つのパラメータが必須となります。
- percentile: 計算したいパーセンタイルの数値を小数で指定します
- こちらだと、1より大きな整数での指定ですが、私の環境ではエラーとなり、0〜1 の小数のみ有効でした。
- percentile_type: パーセンタイルの計算方式として、discrete(離散型) または continuous(連続型) を指定します
ここでは discrete と continuous のメトリクスを定義します。
- name: p90_order_amount_discrete
type: simple
label: 注文金額 P90 (discrete)
agg: percentile
expr: amount
percentile: 0.9
percentile_type: discrete
- name: p90_order_amount_continuous
type: simple
label: 注文金額 P90 (continuous)
agg: percentile
expr: amount
percentile: 0.9
percentile_type: continuous
出力は以下のようになります。
$ dbt sl query --metrics p90_order_amount_discrete,p90_order_amount_continuous
+-----------------------------+---------------------------+
| P90_ORDER_AMOUNT_CONTINUOUS | P90_ORDER_AMOUNT_DISCRETE |
+-----------------------------+---------------------------+
| 9018.5997593403 | 9101 |
+-----------------------------+---------------------------+
通常の SQL と比較します。
>SELECT
PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY amount) AS continuous,
PERCENTILE_DISC(0.9) WITHIN GROUP (ORDER BY amount) AS discrete
FROM DBT_SL_DB.DBT_TYASUHARA.STG_ORDERS;
+------------+----------+
| CONTINUOUS | DISCRETE |
|------------+----------|
| 9018.600 | 9101 |
+------------+----------+
上記より、discreteは値を昇順に並べたときの90番目の値が返っていることが確認できます。continuousは求めたパーセンタイルの順位位置が実際の1行にちょうど一致しない場合に、前後2つの値を線形補間して返します。
join_to_timespine / fill_nulls_with
join_to_timespine: trueとfill_nulls_with: 0プロパティを使うと、対応する時系列がない場合もタイムスパインから補完され、ゼロ埋めが可能です。
例として、すでに定義済みのメトリクスを日別で集計してみます。
出力は以下のようになり、注文が無い日付は出力に含まれません。
$ dbt sl query --metrics order_count \
--group-by metric_time__day \
--order-by metric_time__day \
--limit 10
+-------------------------+-------------+
| METRIC_TIME__DAY | ORDER_COUNT |
+-------------------------+-------------+
| 2018-01-01T00:00:00.000 | 1 |
| 2018-01-02T00:00:00.000 | 1 |
| 2018-01-04T00:00:00.000 | 1 |
| 2018-01-05T00:00:00.000 | 2 |
| 2018-01-07T00:00:00.000 | 1 |
| 2018-01-09T00:00:00.000 | 1 |
| 2018-01-11T00:00:00.000 | 1 |
| 2018-01-12T00:00:00.000 | 1 |
| 2018-01-14T00:00:00.000 | 2 |
| 2018-01-15T00:00:00.000 | 1 |
+-------------------------+-------------+
そこで、join_to_timespine: trueと指定の以下のメトリクスを定義します。
- name: daily_order_count
type: simple
label: 日次注文数
agg: count
expr: 1
join_to_timespine: true
上記に対して同じようにクエリすると以下のようになります。実際の注文の無い日もタイムスパインテーブルの期間がある場合、すべて返されます。
$ dbt sl query --metrics daily_order_count \
--group-by metric_time__day \
--order-by metric_time__day \
--limit 10
+-------------------------+-------------------+
| METRIC_TIME__DAY | DAILY_ORDER_COUNT |
+-------------------------+-------------------+
| 2017-01-01T00:00:00.000 | <nil> |
| 2017-01-02T00:00:00.000 | <nil> |
| 2017-01-03T00:00:00.000 | <nil> |
| 2017-01-04T00:00:00.000 | <nil> |
| 2017-01-05T00:00:00.000 | <nil> |
| 2017-01-06T00:00:00.000 | <nil> |
| 2017-01-07T00:00:00.000 | <nil> |
| 2017-01-08T00:00:00.000 | <nil> |
| 2017-01-09T00:00:00.000 | <nil> |
| 2017-01-10T00:00:00.000 | <nil> |
+-------------------------+-------------------+
以下のようにfill_nulls_with: 0を追加します。
- name: daily_order_count
type: simple
label: 日次注文数
agg: count
expr: 1
join_to_timespine: true
fill_nulls_with: 0
この場合、値がゼロ埋めされます。
$ dbt sl query --metrics daily_order_count \
--group-by metric_time__day \
--order-by metric_time__day \
--limit 10
+-------------------------+-------------------+
| METRIC_TIME__DAY | DAILY_ORDER_COUNT |
+-------------------------+-------------------+
| 2017-01-01T00:00:00.000 | 0 |
| 2017-01-02T00:00:00.000 | 0 |
| 2017-01-03T00:00:00.000 | 0 |
| 2017-01-04T00:00:00.000 | 0 |
| 2017-01-05T00:00:00.000 | 0 |
| 2017-01-06T00:00:00.000 | 0 |
| 2017-01-07T00:00:00.000 | 0 |
| 2017-01-08T00:00:00.000 | 0 |
| 2017-01-09T00:00:00.000 | 0 |
| 2017-01-10T00:00:00.000 | 0 |
+-------------------------+-------------------+
サンプルデータは2018年以降なので、以下のようにフィルタ可能です。
$ dbt sl query --metrics daily_order_count,order_count \
--group-by metric_time__day \
--order-by metric_time__day \
--limit 10 \
--where "{{ TimeDimension('metric_time', 'day') }} >= '2018-01-01'"
+-------------------------+-------------------+-------------+
| METRIC_TIME__DAY | DAILY_ORDER_COUNT | ORDER_COUNT |
+-------------------------+-------------------+-------------+
| 2018-01-01T00:00:00.000 | 1 | 1 |
| 2018-01-02T00:00:00.000 | 1 | 1 |
| 2018-01-03T00:00:00.000 | 0 | <nil> |
| 2018-01-04T00:00:00.000 | 1 | 1 |
| 2018-01-05T00:00:00.000 | 2 | 2 |
| 2018-01-06T00:00:00.000 | 0 | <nil> |
| 2018-01-07T00:00:00.000 | 1 | 1 |
| 2018-01-08T00:00:00.000 | 0 | <nil> |
| 2018-01-09T00:00:00.000 | 1 | 1 |
| 2018-01-10T00:00:00.000 | 0 | <nil> |
+-------------------------+-------------------+-------------+
join_to_timespineのないorder_countで注文がない日は行自体が存在せず(<nil>となる)、daily_order_count(join_to_timespine: true + fill_nulls_with: 0)では、注文がない日も行が生成され0で補完されます。折れ線グラフなど連続した時系列が必要な場合に有効なオプションです。
Derived メトリクス
概要
既存の他のメトリクスを組み合わせて、任意の計算式を用いた計算を行うためのメトリクスです。
Simple メトリクスのexprでも計算式を使用できました。この場合は、行レベルの計算が先でしたが、Derived メトリクスでは、集計後の結果に対して計算式が適用されます。
定義
以下では Derived メトリクスと関連する simple メトリクスのみ抜粋していますが、Derived メトリクスを定義する際は、input_metrics:で使用するメトリクスを指定し、expr:で計算式を設定します。
注意点として、ここでは単一のセマンティックモデル(同じテーブル内の既存のメトリクス)でのDerived メトリクスのため、models:ブロックの中で、semantic_model:と同じ階層にあるmetrics:の下に定義します。
本記事では扱いませんが、複数のモデルをまたぐ(クロスモデル)Derived メトリクスの場合、異なるセマンティックモデルのメトリクスを使用するので、models:ブロックの外側となる、YAMLファイルの最上位階層のmetrics:に定義します。
version: 2
models:
- name: stg_orders
semantic_model:
enabled: true
agg_time_dimension: order_date # metric_time として自動公開される
columns:
- name: order_id
entity:
type: primary
name: orders # "order" はSQL予約語のため "orders" を使用。このname が --group-by の prefix になる(例: orders__status)
- name: customer_id
entity:
type: foreign
name: customer
- name: order_date
granularity: day # 最小粒度。week/month/year への集計も可能
dimension:
type: time
・
・
・
metrics:
- name: order_count
type: simple
label: 注文数
agg: count
expr: 1
- name: distinct_customers
type: simple
label: ユニーク顧客数
agg: count_distinct
expr: customer_id
- name: total_amount
type: simple
label: 合計金額
agg: sum
expr: amount
# --- Derived メトリクス ---
- name: orders_per_customer
type: derived
label: 顧客あたり注文数
# expr: input_metrics で宣言したメトリクス名を変数として使った計算式
expr: order_count / distinct_customers
# input_metrics: expr 内で使うメトリクスを列挙する。
# ここで宣言したメトリクスが expr 内で変数として参照できる。
input_metrics:
- name: order_count
- name: distinct_customers
- name: amount_per_order
type: derived
label: 注文あたり金額
expr: total_amount / order_count
input_metrics:
- name: total_amount
- name: order_count
- name: order_growth_rate
type: derived
label: 前月比注文数成長率
# alias: 同一メトリクスを複数回参照するときに expr 内での変数名を区別する。
# offset_window: 指定期間分だけ過去の値を参照する。
expr: (current_orders - prior_orders) / prior_orders
input_metrics:
- name: order_count
alias: current_orders # expr 内での参照名
- name: order_count
alias: prior_orders
offset_window: 1 month # 1ヶ月前の値を参照
実際にクエリしてみます。
# 顧客1人あたり平均注文数(全体)
$ dbt sl query --metrics orders_per_customer
+---------------------+
| ORDERS_PER_CUSTOMER |
+---------------------+
| 1.596774 |
+---------------------+
# 顧客1人あたり月別の平均注文数
$ dbt sl query --metrics orders_per_customer --group-by metric_time__month
+-------------------------+---------------------+
| METRIC_TIME__MONTH | ORDERS_PER_CUSTOMER |
+-------------------------+---------------------+
| 2018-01-01T00:00:00.000 | 1.208333 |
| 2018-02-01T00:00:00.000 | 1.08 |
| 2018-03-01T00:00:00.000 | 1.129032 |
| 2018-04-01T00:00:00.000 | 1 |
+-------------------------+---------------------+
--compile オプションで生成される SQL を確認すると、input_metricsが1つのサブクエリにまとめられ、外側でexprの計算式が適用される構造になっていることが分かります。
$ dbt sl query --metrics orders_per_customer --compile
SELECT
order_count / distinct_customers AS orders_per_customer
FROM (
SELECT
SUM(1) AS order_count
, COUNT(DISTINCT customer_id) AS distinct_customers
FROM stg_orders
) subq_5
LIMIT 100
offset_windowの利用
offset_window は、Derived メトリクス専用のパラメータで、参照するメトリクスの対象期間を指定した期間分だけ過去にずらして値を取得するための機能です。
成長率や前月比などの計算に使用できます。
注意点として、計算式内で同じメトリクスを複数回参照する場合はaliasで別名をつけ、変数名を区別します。また、offset した先の期間がタイムスパインに含まれている必要があります(例:2018-01 の1ヶ月前 = 2017-12 を参照するにはタイムスパインが2017年から必要)。
以下では、注文数の前月からの成長率を定義しています。
- name: order_growth_rate
type: derived
label: 前月比注文数成長率
# alias: 同一メトリクスを複数回参照するときに expr 内での変数名を区別する。
# offset_window: 指定期間分だけ過去の値を参照する。
expr: (current_orders - prior_orders) / prior_orders
input_metrics:
- name: order_count
alias: current_orders # expr 内での参照名
- name: order_count
alias: prior_orders
offset_window: 1 month # 1ヶ月前の値を参照。単位: day / week / month / quarter / year など
この場合、出力は以下のようになります。また offset_window を使うメトリクスは metric_time での group-by が必須です。
$ dbt sl query --metrics order_count,order_growth_rate --group-by metric_time__month --order-by metric_time__month
+-------------------------+-------------+-------------------+
| METRIC_TIME__MONTH | ORDER_COUNT | ORDER_GROWTH_RATE |
+-------------------------+-------------+-------------------+
| 2018-01-01T00:00:00.000 | 29 | <nil> |
| 2018-02-01T00:00:00.000 | 27 | -0.068966 |
| 2018-03-01T00:00:00.000 | 35 | 0.296296 |
| 2018-04-01T00:00:00.000 | 8 | -0.771429 |
| 2018-05-01T00:00:00.000 | <nil> | <nil> |
+-------------------------+-------------+-------------------+
また、上記で--group-by metric_time__dayのようにして、オフセット期間(offset_window)とクエリ時の集計粒度(group-by)の組み合わせを自由に指定することが可能です。
MetricFlow では、まず最小粒度(日次など)で未集計のデータセットを取得し、指定された期間(1ヶ月)ずらしてオフセット結合を行います。その後、クエリで指定された集計粒度(日次や月次)に合わせてデータを丸めて集計し、最後に計算式が適用されます。
Ratio メトリクス
概要
分子(numerator)・分母(denominator)を明示的に定義してその比率を計算するメトリクスです。Derived でも同様の計算は可能ですが、Ratio は分子÷分母という構造が定義から直接読み取れるため、割合・比率の計算に特化した用途では意図が明確になります。
定義
以下のように、numeratorとdenominatorにメトリクスを指定します。
注意点として、分母と分子で同じメトリクスを使う場合、aliasを指定しないと SQL 内で名前が衝突し、結果が常に 1 になります。
# alias なし(結果が 1 になる)
- name: return_rate
type: ratio
numerator:
name: order_count
filter: "{{ Dimension('orders__status') }} = 'returned'"
denominator:
name: order_count
# alias あり(正しく動作する)
- name: return_rate
type: ratio
numerator:
name: order_count
alias: returned_orders # 分子側に別名をつけて参照先を分離
filter: "{{ Dimension('orders__status') }} = 'returned'"
denominator:
name: order_count
実際にクエリしてみます。
# 返品率(全体)
$ dbt sl query --metrics return_rate
+--------------+
| RETURN_RATE |
+--------------+
| 0.0404040404 |
+--------------+
# 月別返品率:返品ゼロは nil
$ dbt sl query --metrics return_rate --group-by metric_time__month
+-------------------------+--------------+
| METRIC_TIME__MONTH | RETURN_RATE |
+-------------------------+--------------+
| 2018-01-01T00:00:00.000 | 0.1379310345 |
| 2018-02-01T00:00:00.000 | <nil> |
| 2018-03-01T00:00:00.000 | <nil> |
| 2018-04-01T00:00:00.000 | <nil> |
+-------------------------+--------------+
Cumulative メトリクス
概要
時間軸に沿って値を累積集計するメトリクスです。windowで固定幅の移動集計、grain_to_dateで暦の区切りに合わせたリセットタイミングを定義できます。
以下のようなイメージです。
| 設定 | 説明 | 例 |
|---|---|---|
| なし(全期間) | 全期間累積 | 累計注文数、累計売上 |
window: 30 days |
直近30日の移動集計 | 直近30日の注文数 |
grain_to_date: month |
月初からリセット(MTD) | 月初来注文数 |
windowとgrain_to_dateは同時使用できません。
累積メトリクスは非加算(non-additive)です。月別などの粗い粒度でクエリする際は、period_agg で「期間内のどの日次累積値を代表値とするか」を指定します。
| period_agg | 説明 | 例 |
|---|---|---|
| 指定なし(デフォルト) | 期初日時点の累積値 | — |
last |
期末日時点の累積値 | 月末残高、月末時点の累計 |
first |
期初日時点の累積値(デフォルトと同値) | 月初時点の残高 |
average |
期間中の日次累積値の平均 | 月中平均在庫数など |
MetricFlow は内部でタイムスパインと JOIN して最小粒度(日次)の累積値を先に計算し、その後、月別などのクエリ時に period_agg のウィンドウ関数で代表値を選ぶ、という2段階で処理します。累積値は非加算なので単純なSUMでの再集約ができず、period_aggによる明示的な指定が必要です。
なお最小粒度は agg_time_dimensionに指定した時間ディメンションのgranularityで決まります。このモデルではgranularity: dayのため日次が最小粒度です。
agg_time_dimension: order_date # 参照する時間ディメンション
- name: order_date
granularity: day # この設定が最小粒度になる
dimension:
type: time
定義
累積メトリクスを定義する際は、type: cumulativeを指定した上で、上述のパラメータを使用します。
metrics:
- name: cumulative_orders
type: cumulative
label: 累積注文数(全期間)
input_metric: order_count
# window や grain_to_date の期間指定がないため、記録されている全期間の累計(Running Total)を計算
- name: orders_mtd
type: cumulative
label: 注文数(月初来)
input_metric: order_count
grain_to_date: month # 毎月の初めに累積値がリセットされる
- name: rolling_7d_orders
type: cumulative
label: 直近7日注文数
input_metric: order_count
window: 7 days # 常に過去7日間をスライドするウィンドウで累積値を計算
- name: cumulative_orders_first
type: cumulative
label: 累積注文数(期初値)
input_metric: order_count
period_agg: first # period_agg: first により、要求された集計粒度(月次など)における「最初の値」を代表値として返す
- name: cumulative_orders_last
type: cumulative
label: 累積注文数(期末値)
input_metric: order_count
period_agg: last # period_agg: last により、要求された集計粒度(月次など)における「最後の値」を代表値として返す
- name: cumulative_orders_avg
type: cumulative
label: 累積注文数(期間平均)
input_metric: order_count
period_agg: average # period_agg: average により、要求された集計粒度(月次など)における累積値の「平均値」を代表値として返す
実際にクエリしてみます。
全期間累積(月別・日別)
# 月別:各月1日時点の累積値が返る(period_agg 未指定のデフォルト)
$ dbt sl query --metrics cumulative_orders --group-by metric_time__month \
--where "metric_time__month <= '2018-04-01'"
+-------------------------+-------------------+
| METRIC_TIME__MONTH | CUMULATIVE_ORDERS |
+-------------------------+-------------------+
| 2018-01-01T00:00:00.000 | 1 | ← 1/1 当日分のみ
| 2018-02-01T00:00:00.000 | 29 | ← 〜2/1 まで(= 1月全体)
| 2018-03-01T00:00:00.000 | 58 | ← 〜3/1 まで
| 2018-04-01T00:00:00.000 | 91 | ← 〜4/1 まで
+-------------------------+-------------------+
この結果から、period_agg を指定しない累積メトリクスを月単位で集計した場合、各月の期初日時点の累積値が返ることが確認できます。
例えば、1月は 1/1 に注文が1件あり、集計結果としてもその1件のみが返っています。2月の29は、2月の月間件数ではなく、2/1 時点での累積注文数、つまり1月末までに積み上がった累積値 に相当します。
このことから、月粒度で返される値は、各月の初日を含む時点の累積値であることが分かります。
そのため、月別の累計推移を確認する場合には利用できますが、「その月の最終的な累積値」を見たい場合はperiod_agg: lastを使う必要があります。
続けて、日別でクエリしてみます。
# 日別:累積の増加が確認しやすい
$ dbt sl query --metrics cumulative_orders,order_count \
--group-by metric_time__day \
--where "metric_time__day <= '2018-01-10'" \
--order-by metric_time__day
+-------------------------+-------------------+-------------+
| METRIC_TIME__DAY | CUMULATIVE_ORDERS | ORDER_COUNT |
+-------------------------+-------------------+-------------+
| 2018-01-01T00:00:00.000 | 1 | 1 |
| 2018-01-02T00:00:00.000 | 2 | 1 |
| 2018-01-03T00:00:00.000 | 2 | <nil> | # 注文なし(前日と同値)
| 2018-01-04T00:00:00.000 | 3 | 1 |
| 2018-01-05T00:00:00.000 | 5 | 2 |
| 2018-01-06T00:00:00.000 | 5 | <nil> |
| 2018-01-07T00:00:00.000 | 6 | 1 |
| 2018-01-08T00:00:00.000 | 6 | <nil> |
| 2018-01-09T00:00:00.000 | 7 | 1 |
| 2018-01-10T00:00:00.000 | 7 | <nil> |
+-------------------------+-------------------+-------------+
日別で見ると、挙動が分かりやすいです。
order_count に値がある日はその分だけ cumulative_orders が増加し、注文がない日は order_count が<nil>でも、累積値は前日から据え置きとなっています。
period_agg の比較
period_agg:ごとの違いを確認してみます。
$ dbt sl query \
--metrics cumulative_orders,cumulative_orders_first,cumulative_orders_last,cumulative_orders_avg \
--group-by metric_time__month --where "metric_time__month <= '2018-04-01'" \
--order-by metric_time__month
+-------------------------+-------------------+-------------------------+------------------------+-----------------------+
| METRIC_TIME__MONTH | CUMULATIVE_ORDERS | CUMULATIVE_ORDERS_FIRST | CUMULATIVE_ORDERS_LAST | CUMULATIVE_ORDERS_AVG |
+-------------------------+-------------------+-------------------------+------------------------+-----------------------+
| 2018-01-01T00:00:00.000 | 1 | 1 | 29 | 13.935 |
| 2018-02-01T00:00:00.000 | 29 | 29 | 56 | 41.928 |
| 2018-03-01T00:00:00.000 | 58 | 58 | 91 | 73.741 |
| 2018-04-01T00:00:00.000 | 91 | 91 | 99 | 97.9 |
+-------------------------+-------------------+-------------------------+------------------------+-----------------------+
この結果からは、period_agg によって月粒度で返される代表値が変わることが分かります。
cumulative_orders と cumulative_orders_first は同じ値になっており、どちらも期初日時点の累積値を返しています。
一方、cumulative_orders_last はその月の最終日時点での累積値を返すため、月末時点の到達値を確認したい場合はこちらが適しています。
また、cumulative_orders_avg は月内の各日の日次累積値を平均したもので、月の途中経過をならした代表値として解釈できます。
rolling_7d_orders(直近7日移動集計・日別)
order_count(当日の注文数)と同時取得し移動集計の動きを見てみます。
$ dbt sl query --metrics order_count,rolling_7d_orders --group-by metric_time__day \
--where "metric_time__day <= '2018-01-15'" --order-by metric_time__day
+-------------------------+-------------+-------------------+
| METRIC_TIME__DAY | ORDER_COUNT | ROLLING_7D_ORDERS |
+-------------------------+-------------+-------------------+
| 2018-01-01T00:00:00.000 | 1 | 1 |
| 2018-01-02T00:00:00.000 | 1 | 2 |
| 2018-01-03T00:00:00.000 | <nil> | 2 |
| 2018-01-04T00:00:00.000 | 1 | 3 |
| 2018-01-05T00:00:00.000 | 2 | 5 |
| 2018-01-06T00:00:00.000 | <nil> | 5 |
| 2018-01-07T00:00:00.000 | 1 | 6 | # 1/1〜1/7 の7日間に含まれる注文数
| 2018-01-08T00:00:00.000 | <nil> | 5 | # 1/1 の注文が集計範囲から外れるため、当日の注文がなくても 6 → 5 に減少
| 2018-01-09T00:00:00.000 | 1 | 5 |
| 2018-01-10T00:00:00.000 | <nil> | 5 |
| 2018-01-11T00:00:00.000 | 1 | 5 |
| 2018-01-12T00:00:00.000 | 1 | 4 |
| 2018-01-13T00:00:00.000 | <nil> | 4 |
| 2018-01-14T00:00:00.000 | 2 | 5 |
| 2018-01-15T00:00:00.000 | 1 | 6 |
+-------------------------+-------------+-------------------+
この結果から、window: 7 daysを指定した累積メトリクスは、直近7日間の範囲だけを集計する移動ウィンドウとして動作していることが分かります。
そのため、新しい注文が入れば値は増えますが、過去の注文がウィンドウの範囲外に出ると値が減ります。
例えば、2018-01-07 の6は、1/1〜1/7 の7日間に含まれる注文数です。
次の 2018-01-08 では 1/1 の注文が集計範囲から外れるため、当日の注文がなくても 6 → 5 に減少しています。
同様に 2018-01-12 では、1/5 の2件が範囲外に出る影響を受けて値が下がっています。
日々の変化をなめらかに見たい場合や、短期トレンドを確認したい場合に有効です。
orders_mtd(月初来累積・日別)
次に、grain_to_date: monthを指定した orders_mtd を日別で確認してみます。
$ dbt sl query --metrics orders_mtd --group-by metric_time__day --where "metric_time__day <= '2018-04-01'" --order-by metric_
time__day
+-------------------------+------------+
| METRIC_TIME__DAY | ORDERS_MTD |
+-------------------------+------------+
| 2018-01-01T00:00:00.000 | 1 |
| 2018-01-02T00:00:00.000 | 2 |
・
・
| 2018-01-30T00:00:00.000 | 28 |
| 2018-01-31T00:00:00.000 | 29 |
| 2018-02-02T00:00:00.000 | 2 |
| 2018-02-03T00:00:00.000 | 2 |
・
・
| 2018-02-27T00:00:00.000 | 26 |
| 2018-02-28T00:00:00.000 | 27 |
| 2018-03-01T00:00:00.000 | 2 |
| 2018-03-02T00:00:00.000 | 3 |
・
・
| 2018-03-30T00:00:00.000 | 34 |
| 2018-03-31T00:00:00.000 | 35 |
| 2018-04-02T00:00:00.000 | 1 |
| 2018-04-03T00:00:00.000 | 3 |
・
・
| 2018-04-11T00:00:00.000 | 8 |
| 2018-04-12T00:00:00.000 | 8 |
+-------------------------+------------+
この結果から、orders_mtd は月初から当日までの累積値を返しており、月が変わるたびにリセットされることが確認できます。
1月中は cumulative_orders と同様に増加していきますが、2月に入ると 2月分の累積として再度 1 から積み上がります。3月、4月も同様で、それぞれの月初を起点に月内の注文数が累積されています。
さいごに
dbt Semantic Layer における代表的なメトリクスタイプの定義と動作を確認してみました。
こちらの内容がどなたかの参考になれば幸いです。







