セマンティックモデル
VeloDB MCP Service (Apache Doris MCP Server をベースとする) は、AI エージェントが MCP protocol を通じて VeloDB Cloud 内のデータを直接クエリできるようにします。2つのクエリパスを提供します:
- セマンティックレイヤー: 事前に YAML でビジネスメトリクスを定義し、エージェントが自然言語でクエリを行う間にシステムが正しい SQL を生成します(推奨)。
- 生の SQL: メトリクスがマッチしない場合に読み取り専用の SQL クエリにフォールバックします。
このページではセマンティックモデルの作成と管理について説明します。エンドユーザーとしての接続とクエリについては、User Guide を参照してください。
セマンティックモデルとは何か?
セマンティックモデルは、データベーステーブルのビジネス記述です。システムに以下を伝えます:
-
テーブルのプライマリキーが何か(エンティティ)
-
どのフィールドがグループ化に使用できるか(ディメンション)
-
どのフィールドが集計を必要とするか(メジャー)
一度定義されると、ユーザーは自然言語レベルのクエリ(「月別の総注文金額を表示して」)を実行でき、システムが自動的に正しい SQL を生成します。
YAML は仕様で MetricFlow は翻訳者です:「月別の総注文金額」を SELECT DATE_TRUNC('month', order_date), SUM(amount) FROM orders GROUP BY 1 に変換します。
クイックスタート
ステップ 1: YAML ファイルを書く
各 YAML ファイルは1つのテーブルを記述します。models/ ディレクトリの下に置いてください:
# models/orders.yaml
---
semantic_model:
name: orders # model name
db_table: dw.orders # the corresponding VeloDB table
defaults:
agg_time_dimension: order_date # default time dimension
entities:
- name: order_id # primary key
type: primary
expr: order_id
dimensions:
- name: order_date # time dimension
type: time
type_params:
time_granularity: day
- name: channel # categorical dimension
type: categorical
measures:
- name: total_amount # total order amount
agg: sum
expr: amount
- name: order_count # order count
agg: count
expr: order_id
ステップ2: 時間設定の定義
期間比較や前年同期比の時間メトリクスに使用されるカレンダーテーブルを指定するproject.yamlが必要です:
# models/project.yaml
---
time_config:
calendar:
- table: dw.dim_date
column: date_id
grain: day
ステップ3: 検証とコミット
-
Validateをクリックしてモデルが正しいことを確認します
-
検証が通ったら、Commitをクリックしてモデルを有効にします
-
list_metricsを使用して利用可能なメトリクスを確認し、query_metricを使用してデータをクエリします
テーブルが存在するか、カラム名が正しいか、エンティティとディメンションが完全かどうかを確認します。問題がある場合は、具体的なエラーとその場所を返します。
セマンティックモデル構造
完全なsemantic_modelには以下のフィールドが含まれます:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
name | string | ✅ | グローバルに一意なモデル名。小文字で開始し、数字とアンダースコアを含むことができます |
db_table | string | ✅ | VeloDBの物理テーブル、database.table形式、例:dw.orders |
defaults | object | ✅ | デフォルト設定。現在はagg_time_dimensionを含む必要があります |
entities | list | ✅ | テーブルのエンティティ定義。少なくとも1つのtype: primaryメインエンティティが必要 |
dimensions | list | ✅ | グループ化とフィルタリング用のディメンション |
measures | list | 推奨 | 集計定義。定義すると、自動的にクエリ可能なメトリクスになります |
description | string | オプション | モデルのテキスト説明 |
label | string | オプション | 表示名 |
primary_entity | string | 条件付き | entitiesにtype: primaryエンティティがない場合に必須 |
すべての名前(モデル、エンティティ、ディメンション、メジャー)は以下の条件を満たす必要があります:
-
小文字で開始
-
小文字、数字、アンダースコアのみを含む
-
連続する2つのアンダースコア
__を含まない -
最低2文字
✅ order_id、total_amount、user_count
❌ OrderID、order__id、a
エンティティ — テーブルのアイデンティティ
エンティティは行間の一意性と関係性を定義します。すべてのテーブルには1つのメインエンティティが必要です。
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
name | string | ✅ | エンティティ名、このモデル内で一意 |
type | enum | ✅ | エンティティ型(下記の表を参照) |
expr | string | 推奨 | 対応するデータベースカラム。省略可能(デフォルトはname);SQL式もサポートされます |
description | string | オプション | テキスト説明 |
label | string | オプション | 表示名 |
エンティティ型
| 型 | 意味 | 使用する場合 |
|---|---|---|
primary | 主キー。行ごとに一意で、すべてのレコードを網羅 | テーブルのIDカラム。各テーブルには正確に1つの主エンティティが必要 |
foreign | 外部キー。重複とnullを含む可能性 | customer_idやproduct_idなど、他のテーブルに結合するカラム |
unique | 一意キー。行ごとに一意だが、すべてのレコードを網羅しない可能性 | 例:メールアドレスやID番号 |
natural | 自然キー。現実世界の一意識別子 | 例:商品バーコードや従業員番号 |
例:ordersテーブルのエンティティ定義
entities:
- name: order_id # primary key: the unique ID of each order
type: primary
expr: order_id
- name: customer # foreign key: joins to the users table
type: foreign
expr: user_id
- name: order_ref # foreign key + SQL expression
type: foreign
expr: substring(trace_id FROM 1 FOR 8)
テーブルに type: primary エンティティがない場合は、モデルのトップレベルで primary_entity: entity_name を使用してください。
Dimensions — データのグループ化方法
Dimensionsはデータのグループ化とフィルタリングの方法を定義します。時間ディメンションとカテゴリカルディメンションの2つのタイプがあります。
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | ディメンション名 |
type | enum | ✅ | time または categorical |
type_params | object | Required for time | 時間粒度の設定(以下を参照) |
expr | string | Recommended | 対応するカラムまたはSQL式 |
is_partition | bool | Optional | パーティションカラムかどうか。デフォルトは false |
description | string | Optional | テキスト説明 |
label | string | Optional | 表示名 |
Time Granularity (time_granularity)
| Granularity | Meaning | Example |
|---|---|---|
day | 日別 | 2025-01-15 |
week | 週別 | 2025-W03 |
month | 月別 | 2025-01 |
quarter | 四半期別 | 2025-Q1 |
year | 年別 | 2025 |
hour | 時別 | 2025-01-15 14:00 |
minute | 分別 | 2025-01-15 14:30 |
Example
dimensions:
- name: order_date # order date (by day)
type: time
type_params:
time_granularity: day
expr: order_date
- name: order_month # order month (by month)
type: time
type_params:
time_granularity: month
expr: order_date # same column, different granularity
- name: channel # channel (categorical)
type: categorical
expr: channel
- name: status_label # with a SQL expression
type: categorical
expr: concat(status, '_', channel)
Measures — 集約
Measuresはデータ列に対する集約を定義します。各measureは自動的に同じ名前のクエリ可能なmetricを生成します。
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | Measure名(metric名にもなります) |
agg | enum | ✅ | 集約タイプ(下記の表を参照) |
expr | string | 推奨 | 集約する列またはSQL式 |
description | string | オプション | Metricの説明 |
label | string | オプション | 表示名 |
create_metric | bool | オプション | falseに設定するとmetricを自動生成しません。デフォルトはtrue |
agg_time_dimension | string | オプション | モデルのデフォルト時間ディメンションを上書きします |
集約タイプ
| Type | 意味 | 一般的な用途 |
|---|---|---|
sum | 合計 | 総額、総数 |
count | カウント | 注文数、ユーザー数 |
count_distinct | 重複除去カウント | ユニークユーザー、アクティブデバイス |
average | 平均 | 平均額、平均時間 |
min | 最小値 | 最低価格、最早時刻 |
max | 最大値 | 最高価格、最遅時刻 |
median | 中央値 | 注文額の中央値 |
percentile | パーセンタイル | P99レイテンシ、P95額(agg_params.percentileが必要) |
sum_boolean | Boolean合計 | コンバージョン数、合格数 |
例
measures:
- name: total_amount # total order amount
description: "Sum of all order amounts"
agg: sum
expr: amount
label: "Total Amount"
- name: order_count # order count
agg: count
expr: order_id
- name: unique_customers # distinct customers
description: "Number of distinct customers who placed an order"
agg: count_distinct
expr: user_id
- name: p99_amount # P99 order amount
agg: percentile
expr: amount
agg_params:
percentile: 0.99
- name: internal_counter # not exposed as a metric
agg: sum
expr: raw_value
create_metric: false
完全な例
以下は、eコマースシナリオにおける完全なsemantic-model定義です — ordersテーブル:
# models/orders.yaml — orders fact table
---
semantic_model:
name: orders
description: "E-commerce order fact table; each row is one order"
db_table: dw.orders
defaults:
agg_time_dimension: order_date
# ── Entities ──
entities:
- name: order_id
description: "Order primary key"
type: primary
expr: order_id
- name: customer
description: "Associated user"
type: foreign
expr: user_id
- name: product
description: "Associated product"
type: foreign
expr: product_id
# ── Dimensions ──
dimensions:
- name: order_date
description: "Order date (by day)"
type: time
type_params:
time_granularity: day
expr: order_date
- name: order_month
description: "Order month"
type: time
type_params:
time_granularity: month
expr: order_date
- name: channel
description: "Order channel"
type: categorical
expr: channel
- name: status
description: "Order status"
type: categorical
expr: status
# ── Measures ──
measures:
- name: total_amount
description: "Total order amount"
label: "Total Amount"
agg: sum
expr: amount
- name: order_count
description: "Total order count"
label: "Order Count"
agg: count
expr: order_id
- name: unique_customers
description: "Distinct customers who placed an order"
label: "Distinct Customers"
agg: count_distinct
expr: user_id
- name: avg_amount
description: "Average order amount"
label: "Average Order Value"
agg: average
expr: amount
Companion: usersテーブルとproductsテーブル
# models/users.yaml — users dimension table
---
semantic_model:
name: users
description: "User dimension table"
db_table: dw.users
defaults:
agg_time_dimension: register_date
entities:
- name: user_id
type: primary
expr: user_id
dimensions:
- name: register_date
type: time
type_params:
time_granularity: day
- name: city
type: categorical
- name: level
type: categorical
measures:
- name: user_count
agg: count
expr: user_id
# models/products.yaml — products dimension table (pure dimension table, no measures, so defaults is omitted)
---
semantic_model:
name: products
description: "Product dimension table"
db_table: dw.products
entities:
- name: product
type: primary
expr: product_id
dimensions:
- name: product_name
type: categorical
expr: name
- name: category
type: categorical
expr: category
- name: brand
type: categorical
expr: brand
高度なメトリック定義
measuresから自動生成される単純なメトリック以外に、metric:ドキュメントを使用して高度なメトリックを定義できます。高度なメトリックは、既存のmeasureやmetricsを組み合わせて、より複雑なロジックを実装します。4つのタイプがサポートされています:
| Type | 意味 | 典型的なシナリオ |
|---|---|---|
ratio | Ratio metric: 分子 ÷ 分母 | コンバージョン率、利益率、シェア |
derived | Derived metric: 既存のmetricsに対する式 | 前期比成長率、前年同期比変化、加重計算 |
cumulative | Cumulative metric: 時間窓での累積 | 過去7日間の売上、月次累計登録数 |
conversion | Conversion metric: 2つのイベント間のコンバージョン分析 | 注文コンバージョン率、登録コンバージョン率 |
Ratio Metrics
2つのメトリックの比率を計算します。例:ユーザーあたりの注文数 = 注文数 / ユーザー数
# models/orders_per_user.yaml
---
metric:
name: orders_per_user
description: "Orders per user: order count / user count"
type: ratio
type_params:
numerator: order_count # numerator: references an existing metric
denominator: user_count # denominator: references an existing metric
分子と分母の両方は、既に定義されたメトリック名である必要があります(単純なメトリックまたは他の高度なメトリックのいずれか)。
Derived Metrics
式を通じて1つ以上の既存のメトリックから算出されます。最も頻繁に期間対期間および年対年の計算に使用されます。
# models/revenue_growth.yaml — period-over-period growth
---
metric:
name: revenue_growth
description: "Revenue period-over-period growth rate"
type: derived
type_params:
expr: (current_revenue - prev_revenue) / prev_revenue
metrics:
- name: total_amount # current-period revenue
alias: current_revenue
- name: total_amount # prior-period revenue (same metric, with an offset)
alias: prev_revenue
offset_window: 1 month # shift back by one time window
| パラメータ | 説明 |
|---|---|
expr | 計算式;各入力メトリックをそのaliasで参照する |
metrics | 入力メトリックのリスト |
name | 参照されるメトリック名 |
alias | exprで使用されるエイリアス |
offset_window | 時間オフセット、例:1 month、7 days、1 year |
offset_to_grain | オフセット先の粒度、例:month、year |
累積メトリック
時間ウィンドウにわたってメトリックを蓄積する、例:「過去7日間の売上」
# models/weekly_sales.yaml
---
metric:
name: weekly_sales
description: "Sales over the last 7 days"
type: cumulative
type_params:
measure:
name: total_amount
window: 7 days # time window: the past 7 days
| パラメータ | 説明 |
|---|---|
measure | 参照される measure 名(semantic_model の measures から) |
window | 時間窓の形式 number granularity、例:28 days、4 weeks、3 months |
grain_to_date | オプション。指定された粒度まで累積する、例:month(月初来)、year(年初来) |
Conversion Metrics
あるイベント(ベース)から別のイベント(コンバージョン)にユーザーがコンバートする率を測定します。ユーザーファネルの分析によく使用されます。
# models/order_conversion.yaml
---
metric:
name: register_to_order_conversion
description: "Registration-to-order conversion rate"
type: conversion
type_params:
conversion_type_params:
base_measure: # base event (registration)
name: user_count
conversion_measure: # conversion event (order)
name: order_count
entity: user # join entity: the dimension to compute conversion by
calculation: conversion_rate # calculation method
| パラメータ | 説明 |
|---|---|
base_measure | ベースイベントのmeasure名 |
conversion_measure | コンバージョンイベントのmeasure名 |
entity | コンバージョンを計算するjoinエンティティ(通常はuserまたはsession) |
calculation | conversion_rate(レート)またはconversions(絶対数) |
window | オプション。コンバージョンウィンドウ、例:7 days |
一般的なシナリオ
シナリオ1:異なる粒度でdimensionとして同じカラムを使用する
単一のdateカラムで、day、week、monthのdimensionを一度に定義できます:
dimensions:
- name: order_date
type: time
type_params:
time_granularity: day
expr: order_date
- name: order_week
type: time
type_params:
time_granularity: week
expr: order_date # same column!
- name: order_month
type: time
type_params:
time_granularity: month
expr: order_date # same column!
シナリオ2: SQL式の使用
列名が直感的でない場合、または計算フィールドが必要な場合は、SQL式を使用します:
dimensions:
- name: user_label
type: categorical
expr: concat(level, '_', city) # concatenated field
entities:
- name: user_short_id
type: foreign
expr: substring(trace_id FROM 1 FOR 8) # substring
measures:
- name: net_amount
agg: sum
expr: coalesce(amount, 0) - coalesce(discount, 0) # computed field
substring、concat、coalesce、castなどの標準SQL関数。これらの式は物理検証中に認識され、列名チェックをスキップします。
シナリオ3: パーティション化されたテーブル
テーブルにパーティション列がある場合は、is_partition: trueでマークします:
dimensions:
- name: ds
type: time
type_params:
time_granularity: day
is_partition: true # mark as the partition column
expr: ds
シナリオ4: 内部メジャーの非表示
一部のメジャーは中間計算のみに使用され、エンドユーザーに公開すべきではありません。create_metric: falseを設定してください:
measures:
- name: total_amount # ✅ public metric
agg: sum
expr: amount
- name: _raw_count # ❌ not exposed
agg: count
expr: order_id
create_metric: false
高度な機能
フィルター
measure定義またはmetric定義にSQLフィルター条件を追加できます。フィルターは集計前に適用されます。
-
measuresエントリのfilter:フィールド — 単一のmeasureのデータ範囲を制限します -
metric:のfilter:フィールド — metric全体のデータ範囲を制限します -
measureのinput_measures[].filter:— 高度なmetricによって参照されるmeasureを制限します
# Example 1: measure-level filter — only the total amount of "completed" orders
measures:
- name: completed_amount
description: "Sum of completed order amounts"
agg: sum
expr: amount
filter: {{ render_dimension_template('status') }} = 'completed'
# Example 2: metric-level filter
---
metric:
name: premium_user_orders
description: "Order count for premium users"
type: simple
type_params:
measure:
name: order_count
filter: {{ render_dimension_template('user_level') }} = 'premium'
-
YAMLでは、ディメンションを
{{ Dimension('qualified_name') }}または{{ render_dimension_template('dimension_name') }}で参照してください -
エンティティを
{{ Entity('entity_name') }}または{{ render_entity_template('entity_name') }}で参照してください -
通常のSQL条件を続けてください。例:
= 'value'、IN ('a', 'b') -
query_metricのwhereパラメータは生のSQLを直接受け入れます(例:"channel = 'APP'")。コンパイラが自動的にMetricFlowテンプレート構文に変換します
Saved Queries
メトリクス + グループ化 + フィルターの頻繁に使用される組み合わせを、ユーザーが直接呼び出せるクエリテンプレートとして保存します。
# models/weekly_report.yaml
---
saved_query:
name: weekly_revenue_report
description: "Weekly revenue report: total order amount and order count grouped by channel"
label: "Weekly Revenue Report"
query_params:
metrics:
- total_amount
- order_count
group_by:
- order_id__order_week # group by week
- order_id__channel # group by channel
order_by:
- "-order_id__order_week" # descending by week
limit: 52
| フィールド | 説明 |
|---|---|
metrics | クエリするメトリック名のリスト |
group_by | グループ化ディメンション、entity_name__dimension_name 形式(二重アンダースコアで結合) |
order_by | ソート;- プレフィックスは降順を意味する |
where | フィルター条件(フィルターと同じ構文) |
limit | 行の最大数 |
entity_name__dimension_name(二重アンダースコア)。例えば、order_id__order_date は orders テーブルの order_date ディメンションです。
Non-additive Measures & Slowly Changing Dimensions (SCD Type II)
一部のメジャーは単純に合計できない(在庫や口座残高など)ため、特定のディメンションに沿ったスナップショット値が必要です。
# Non-additive measure: inventory (month-end snapshot)
measures:
- name: monthly_inventory
description: "Month-end inventory"
agg: sum
expr: inventory_count
non_additive_dimension:
name: snapshot_date # the non-additive dimension
window_choice: max # take the maximum within the time window
window_groupings:
- product # snapshot grouped by product
SCD Type II (slowly changing dimensions): ディメンションテーブルに有効期間がある場合、開始と終了のディメンションをマークします:
# Mark SCD Type II in the dimension table
dimensions:
- name: valid_from
description: "Validity start time"
type: time
type_params:
time_granularity: day
validity_params:
is_start: true # mark as the start time
- name: valid_to
description: "Validity end time"
type: time
type_params:
time_granularity: day
validity_params:
is_end: true # mark as the end time
Null補完とタイムライン整列
# Replace NULL with 0 (useful so count-type metrics show 0 on dates with no data)
metric:
name: daily_orders
type: simple
type_params:
measure:
name: order_count
fill_nulls_with: 0 # show 0 on dates with no data
join_to_timespine: true # align to the timeline (fill in missing dates)
| Parameter | Description |
|---|---|
fill_nulls_with | 集計結果のNULLを指定した値(通常は0)で置き換える |
join_to_timespine | メトリック結果をタイムラインテーブルと結合し、すべての日/月/年に行を持たせる(欠損日付はNULLまたは0で埋める) |
ネイティブテーブル参照形式
db_tableの短縮形に加えて、MetricFlowのネイティブnode_relation形式もサポートされており、3部構成のカタログ参照も含まれます:
# Two-part: database.table
node_relation:
schema_name: dw
alias: orders
# Three-part: catalog.database.table
node_relation:
database: catalog
schema_name: dw
alias: orders
# db_table also supports the three-part form
db_table: catalog.dw.orders
累積メトリクスの集計モード
累積メトリクスは、時間ウィンドウ内での集計を制御する3つのperiod_aggモードをサポートしています:
# last: take the value of the last day in the window (default behavior)
metric:
name: end_of_week_inventory
type: cumulative
type_params:
cumulative_type_params:
measure:
name: inventory_count
window: 7 days
period_agg: last # take the last day's value
# average: daily average within the window
period_agg: average # 7-day average
# first: the value of the first day in the window
period_agg: first # take the first day's value
period_agg | 説明 |
|---|---|
last | ウィンドウ内の最終日の値(デフォルト) |
average | ウィンドウ内の日次平均 |
first | ウィンドウ内の初日の値 |
コンバージョンメトリクスの定数プロパティ
コンバージョンメトリクスでは、constant_propertiesを使用して、2つのイベント間で一定に保たれる必要があるプロパティを指定します:
# Analyze conversion by "traffic source", requiring the source to be the same across both events
metric:
name: register_to_order_by_source
type: conversion
type_params:
conversion_type_params:
base_measure:
name: user_count
conversion_measure:
name: order_count
entity: user
constant_properties:
- base_property: order_id__channel # the base event's property
conversion_property: order_id__channel # the conversion event's property (must match)
Metric Time Granularity & Offset Grain
メトリックレベルのtime_granularity: メトリック定義内で直接時間粒度を設定できます(クエリ時のデフォルトを上書きします):
metric:
name: monthly_revenue
type: simple
time_granularity: month # this metric defaults to monthly aggregation
type_params:
measure:
name: total_amount
offset_to_grain: 派生メトリックにおいて、オフセットを指定されたgrain(デフォルトの日レベルではなく)に揃えます:
metric:
name: yoy_growth
type: derived
type_params:
expr: (current - prev) / prev
metrics:
- name: total_amount
alias: current
- name: total_amount
alias: prev
offset_window: 1 year
offset_to_grain: month # offset to month grain (rather than day)
エンティティロール
同じエンティティ(user_idなど)がテーブル内で複数の役割を果たすことがあります。例えば、ordersテーブルのuser_idは「購入者」と「紹介者」の両方になります。それらを区別するにはroleを使用してください:
entities:
- name: user
type: foreign
expr: buyer_id
role: buyer # this user entity's role is "buyer"
- name: user
type: foreign
expr: referrer_id
role: referrer # this user entity's role is "referrer"
roleが指定されていない場合、デフォルトロールはエンティティ名と等しくなります。
ベストプラクティス
-
テーブルごとに1つのファイル。 明確で保守しやすい構造のために、ファイル名を
table_name.yamlにしてください。✅
orders.yaml、users.yaml、products.yaml -
エンティティ、次にディメンション、次にメジャーの順で定義する。 エンティティはセマンティックモデルの骨格であり、ディメンションはグルーピングを提供し、メジャーはクエリターゲットです。この順序で記述することで省略を避けることができます。
-
すべてのメジャーに
descriptionを記述する。 エンドユーザーはメトリック名と説明を見ます。適切な説明により、YAMLを読まなくてもメトリックを理解できます。 -
同じ時間カラムで複数の粒度ディメンションを定義できる。 例えば、
order_dateカラムは日、週、月、四半期、年の粒度を同時に持つことができます。 -
外部キーエンティティには意味のあるビジネス名を使用する。 エンティティ名
customerはuser_idよりも理解しやすく、「user_idカラム」ではなく「顧客」の概念を表します。 -
コミット前に検証する。 YAMLを変更するたびにValidateをクリックしてください。システムはテーブルの存在、カラム名の正確性、命名規則をチェックします。合格後にのみコミットしてください。
-
メジャー名はモデル内で一意である必要がある。 メジャー名はモデル間で重複可能ですが、メトリックのオーバーライドが発生するため、グローバルに一意にすることが最善です。
よくあるエラーとトラブルシューティング
| エラーメッセージ | 原因 | 修正方法 |
|---|---|---|
Table xxx does not exist | db_tableが指すテーブルが存在しない | テーブル名のスペルをチェックし、データベース名とテーブル名の両方が正しいことを確認 |
measure references missing column: dw.orders.xxx | メジャーが参照するカラムがテーブルに存在しない | exprが実際のカラム名と一致することをチェック(大文字小文字に注意) |
entity references missing column | エンティティのexprが参照するカラムが存在しない | 上記と同様。SQL式(例:substring(...))の場合は、関数名とカラム名を確認 |
Duplicate measure 'xxx' defined in 2 models | 2つのモデルが同じ名前のメジャーを定義している | メジャーの1つをリネームしてグローバルに一意にする |
Duplicate semantic_model name | 2つのファイルが同じモデル名を使用している | モデルの1つをリネーム |
Did not find exactly one project configuration | project.yamlが不足している | time_configを含むproject.yamlを作成 |
'xxx' does not match '^(?!.*__)...$' | 名前が命名規則に違反している | 小文字で開始し、二重アンダースコアを削除し、2文字以上にする |
No staging changes to validate | 検証する変更がない | まずYAMLファイルをアップロードまたは編集してから、Validateをクリック |
-
VeloDBでテーブルが存在することを確認:
DESCRIBE dw.orders -
カラム名が大文字小文字を含めて完全に一致することを確認
-
YAMLのインデントが正しいことをチェック(タブではなくスペースを使用)
-
すべての名前が小文字開始のルールに従っていることを確認
VeloDB MCPサービスでのセマンティックモデル管理
ワークスペース
ワークスペースはセマンティックモデルの分離されたコンテナです。各ワークスペースは独自に以下を持ちます:
-
モデルファイル(YAML定義)
-
メトリックリスト(
list_metricsはこのワークスペースのメトリックのみを参照) -
クエリエンジンインスタンス(MetricFlowコンパイラ)
-
VeloDB接続プール
ワークスペースAのメトリックはワークスペースBから完全に見えません。これはチーム、プロジェクト、環境による分割に適しています。
ワークスペース名は文字で始まり、文字、数字、アンダースコアのみを含む必要があります。例:marketingまたはfinance_v2。
3つのワークスペース状態
check_service_healthを呼び出して各ワークスペースの実行時状態を確認します。ワークスペースは常に3つの状態のうち1つです:
| 状態 | アイコン | 意味 | トリガー |
|---|---|---|---|
| healthy | 🟢 | 正常に動作中。セマンティックモデルが正常に読み込まれ、メトリックがクエリ可能。 | YAMLファイルがコミットされ、ブートストラップ解析が成功し、MetricFlowエンジンが準備完了。 |
| no_models | ⚪ | 空のワークスペース。まだYAMLファイルがアップロードされていない。 | 新規作成されたワークスペース、またはすべてのファイルが削除された。 |
| not_ready | 🔴 | 読み込み失敗。ファイルは存在するがセマンティックマニフェストにコンパイルできない。 | YAML構文エラー、テーブル不足、project.yaml不足、MetricFlow検証失敗など。validateエラーメッセージを確認。 |
┌──────────────┐ upload YAML ┌──────────────┐ commit OK ┌──────────────┐
│ no_models │ ──────────────→ │ not_ready │ ───────────────→ │ healthy │
│ (empty) │ │ (to fix) │ │ (running) │
└──────────────┘ └──────────────┘ └──────────────┘
↑ │
│ upload a bad YAML │
└──────────────────────────────────┘
各リロード後、システムはバージョン番号、メトリック数、および読み込みが成功したかどうかを記録します。check_service_healthによって返されるmetric_countを使用して、現在読み込まれているメトリックの数を確認してください。
二層ストレージ:Active StoreとStaging Store
各ワークスペースは内部的に二つのストレージ層を持っています:
| ストレージ層 | テーブル | 目的 |
|---|---|---|
| Active Store (live) | active_store_{workspace} | コミットされ読み込まれたモデル。クエリエンジンはこのバージョンを使用します。ファイルは読み取り専用です。 |
| Staging Store (pending) | staging_store_{workspace} | ユーザーによってアップロードまたは編集された保留中の変更。追加/変更/削除が許可されています。検証に合格した後、Activeに昇格されます。 |
Staging Store Active Store
┌─────────────┐ commit ┌─────────────┐
│ edit / add │ ─────────→ │ query use │
│ validate ✓ │ │ read-only │
│ discard ✗ │ │ │
└─────────────┘ └─────────────┘
↑ ↑
user edits query engine
更新フロー
セマンティックモデルの更新は 編集 → 検証 → コミット → 自動リロード のフローに従います:
| ステップ | アクション | 説明 |
|---|---|---|
| 1 | YAML のアップロード/編集 | ファイルがStaging Store に入ります(実行中のクエリに影響しません) |
| 2 | 検証 | 必須!システムがテーブルの存在、カラムの正確性、YAML構文、MetricFlowセマンティックルール、命名ルール、クロスモデル重複名をチェックします |
| 3 | コミット | Staging → Active。システムが自動的にエンジンリロードをトリガーします(手動再起動不要) |
| 4 | ⟳ 自動リロード | バックグラウンドスレッドが新しいモデルを解析し、JSONマニフェストをコンパイルし、ツールルーティングを更新します。通常2-5秒で完了します |
検証を通過していないStagingはコミット時に拒否され、"Staging must be validated before commit"が返されます。
権限モデル
admin ユーザーのみがセマンティックモデルを管理できます:
| アクション | admin | 一般ユーザー |
|---|---|---|
| セマンティックモデルの表示 | ✅ | ✅ |
メトリクスクエリ(query_metric) | ✅ | ✅ |
メトリクス一覧(list_metrics) | ✅ | ✅ |
| YAML のアップロード/編集/削除 | ✅ | ❌ |
| 検証 / コミット / 破棄 | ✅ | ❌ |
| ワークスペースの作成/削除 | ✅ | ❌ |
SQL 実行(execute_query) | ✅ | ✅(制限あり) |
デフォルトサンプルワークスペース
初回起動時に、システムは自動的に完全なシードデータを持つ example ワークスペースを作成します:
| コンテンツ | 説明 |
|---|---|
dw.orders | 注文テーブル(12行のモックデータ):order_id、user_id、product_id、amount、channel、status、order_date |
dw.users | ユーザーテーブル(5行のモックデータ):user_id、name、city、level、register_date |
dw.products | 製品テーブル(5行のモックデータ):product_id、name、category、brand、price |
dw.dim_date | 日付ディメンション(カレンダー)テーブル、タイムライン調整と累積計算に使用 |
| セマンティックモデル YAML | orders.yaml、users.yaml、products.yaml + project.yaml(active_store_example に自動注入) |
サンプルメトリクスには、ordersモデルから total_amount(総注文金額)、order_count(注文数)、avg_amount(平均注文額)、unique_users(個別ユーザー)、usersモデルから user_count(ユーザー数)が含まれます。
自動シーディングを無効にするには、設定で seed_example: false を設定してください。
WebUI 管理インターフェース
WebUI(ブラウザインターフェース)
http://<server-address>:<port>/mcp/web にアクセスしてサインインし、グラフィカル管理インターフェースを使用します:
| ページ | URL | 機能 |
|---|---|---|
| サインイン | /mcp/web/login | VeloDBアカウントでサインイン(admin:adminがデフォルト管理者) |
| ホーム | /mcp/web | ワークスペース一覧;ワークスペースの切り替え、作成、削除 |
| モデル管理 | /mcp/web/models?workspace=xxx | Active と Staging のファイル一覧表示;編集、アップロード、削除 |
| ファイルエディター | /mcp/web/{filename}?workspace=xxx | 構文ハイライト付きでYAMLファイルをオンライン編集 |
主要なアクションボタン(adminのみ):
| ボタン | アクション |
|---|---|
| 検証 | すべてのStaging変更を検証(物理 + セマンティック検証 + 重複検出) |
| コミット | 検証済みのStagingをActiveに昇格し、エンジンリロードをトリガー |
| 破棄 | すべてのStaging変更を破棄してActiveバージョンに戻す |
| リロード | エンジンリロードを手動でトリガー(通常はコミット後に自動実行) |
| + 新規 | 新しいYAMLファイルを作成 |
次のステップ
- ユーザーガイド — VeloDB MCP Service をAIエージェントに接続し、自然言語でデータをクエリします。