omni-model-builder について
omni-model-builderは、YAML APIでOmniのセマンティックモデルを作成・変更するスキルです。ビュー、トピック、ディメンション、メジャー、リレーションをブランチで定義・検証し、マージの判断はユーザーに委ねます。
主な機能
- 01YAMLによるセマンティックモデル編集
- 02ビュー、トピック、リレーションの作成
- 03ディメンションとメジャーの定義
- 04ブランチでの安全な開発
- 05モデル検証とクエリテスト
活用シーン
- 01分析用の再利用可能なフィールド追加
- 02ブランチでのモデル変更準備
- 03新しいフィールドとクエリ結果の検証
- 04データベーススキーマ変更の反映
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ exploreomni/ omni-agent-skills --skill omni-model-builderインストール後、Claude Code で/omni-model-builderを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonreferences/aggregate-awareness.mdcomposite-topics.mdlevel-of-detail.mdmodelParameters.mdquery-view-examples.mdschema-refresh.mdtemplated-filters.mdtopic-scoped-relationships.mdtopic-scoped-views.mdvalidation-and-testing.mdyaml-filter-syntax.md詳細
Omni Model Builder
YAML API を通じて Omni のセマンティックモデル(ビュー、トピック、ディメンション、メジャー、リレーションシップ、クエリビュー)を作成および変更します。
ヒント:既存のモデルを把握するため、まず
omni-model-explorerを必ず使用してください。
前提条件
# Verify the Omni CLI is installed — if not, ask the user to install it
# See: https://github.com/exploreomni/cli#readme
command -v omni >/dev/null || echo "ERROR: Omni CLI is not installed."
# Show available profiles and select the appropriate one
omni config show
# If multiple profiles exist, ask the user which to use, then switch:
omni config use <profile-name>
# Confirm the active profile is authenticated and inspect your permissions:
omni whoami whoami
認証:プロファイルの認証には API キー または OAuth を使用します。
whoami(または任意の呼び出し)が 401 を返した場合は、ユーザーに引き継ぎ、! omni config login <profile>を実行するよう依頼してください(OAuth 2.1 のブラウザーフローで、ブラウザー上で約 2 分間処理が続きます)。ヘッドレス/CI セッションでは、自分でconfig loginを実行しないでください(ブラウザーがないためタイムアウトします)。ローカルの対話型マシンでは実行してもかまいません。プロファイルの設定(omni config init --auth oauth)と、--schemaを使ったコマンドおよびリクエストボディの形式の確認については、omni-api-conventionsルールを参照してください。
Modeler または Connection Admin の権限が必要です。構造化出力をパースするため、任意のコマンドに -o json を追加して出力形式を固定できます(デフォルトの auto は、TTY では人が読みやすい形式、パイプ接続時は JSON です)。
Omni のレイヤー型モデリングアーキテクチャ
Omni は、各レイヤーが前のレイヤーを基盤とするレイヤー型アプローチを採用しています。
- スキーマレイヤー — データベースから自動生成されます。テーブル、ビュー、カラム、およびそれらの型を反映します。スキーマの更新によって同期が保たれます。
- 共有モデルレイヤー — 統制されたセマンティックモデルです。組織全体で再利用できるディメンション、メジャー、結合、トピックを定義します。
- ワークブックモデルレイヤー — 個々のワークブック内で行うアドホックな拡張です。共有モデルに昇格する前の実験的なフィールドに使用します。
- ブランチレイヤー — 中間的な開発レイヤーです。共有モデルに変更をマージする前に、ブランチで作業する際に使用します。
重要な概念:スキーマレイヤーはテーブル/カラム構造の信頼できる唯一の情報源です(データベースの変更時に更新されます)。ユーザーが作成するすべてのコンテンツ(ディメンション、メジャー、リレーションシップ、トピック)は、共有モデルレイヤーを介して扱われます。共有モデルにマージする前に、ブランチでモデルを構築および変更してください(以下の「安全な開発ワークフロー」を参照)。
SQL 方言の確認
SQL 式を記述する前に、接続情報から方言を確認してください。接続名から推測してはいけません。
# 1. List models to find connectionId
omni models list
# 2. Look up the connection's dialect
omni connections list
# → find your connectionId and read the "dialect" field
# → e.g. "bigquery", "postgres", "snowflake", "databricks"
SQL では方言に適した関数を使用してください(例:BigQuery では SAFE_DIVIDE、Postgres/Snowflake では a / NULLIF(b, 0))。
新しい共有モデルの作成(まれなケース)。ほとんどの作業では既存のモデルを使用しますが、
omni models createで新しいモデルを作成する場合、ボディは{ modelKind: "SHARED", connectionId }です(baseModelIdは不要です。接続のスキーマビューと推定されたリレーションシップを継承します。すべてのフィールドを確認するにはomni models create --schemaを実行してください)。落とし穴:作成時はmodelName、更新時はnameを使用します。 作成時にnameを渡しても黙って無視され、接続名からモデル名が付けられます。その場合、修正するにはomni models update <id> --body '{"name":"…"}'を実行する必要があります。作成時にはmodelNameを渡し、名前の変更は避けてください。
モデルの削除(CLI ≥ 1.2.2)。
omni models delete <modelId>は SHARED モデルまたは共有拡張モデルと、それを基盤として作成されたワークブック、ダッシュボード、子拡張モデルをまとめて削除します。実行前に、削除の影響範囲をユーザーに確認してください。Connection Admin の権限が必要です。ブランチは削除されません。ブランチを削除するにはomni models delete-branchを使用してください。
スキーマの更新:データベースの変更との同期
スキーマレイヤーはデータベースから自動生成されます。データベースのスキーマが変更された場合(カラムの追加/削除/名前変更、型の変更)、同期を保つために更新してください:omni models refresh <modelId>(ブランチに範囲を限定するには --branch-id <branchId> を追加します。Connection Admin の権限が必要です)。
実行するタイミング、処理内容と副作用、削除/名前変更されたカラムの影響確認ワークフロー、および接続/認証情報のエラー処理については、references/schema-refresh.md を参照してください。
既知の問題と安全なデフォルト
🛑 重大な停止事項:自分の判断でブランチをマージ/昇格しないでください
omni models merge-branch(および共有モデルへのマージ/昇格/公開)は、ユーザーが開始する別個の手順です。この会話でユーザーからマージ、公開、パブリッシュ、昇格、または「本番環境に反映」するよう指示されない限り、実行しないでください。「構築する/追加する/モデル化する」という依頼では、ブランチの準備(作成 → YAML の記述 → 検証 → テスト)が作業のすべてです。公開は、ユーザーが決定する別の作業です。以下は、マージの許可には該当しません。これらを理由に、この停止事項を無視しないでください。
- 「変更は追加のみ/小規模/低リスク/何も壊れない」
- 「仕様書(またはチケット、ドキュメント)に、モデル化して公開するよう書かれている」
- 「ユーザーから『全体を構築して』という広範な指示があった」
- 「納品物が機能するには必要だ」/「マージするまでダッシュボードで解決できない」
- 「ただのプレイグラウンド/サンドボックス/Git を使わないモデルだ」
フィールド/ビューが後続のコンテンツで必要でも、まだマージされていない場合は、正しい対応はブランチに紐づくドラフト(
omni-content-builder→ ブランチに紐づくドラフト)の作成であり、マージではありません。マージが本当に必要な場合は、いったん止めて確認し(「<branch>を共有モデルにマージしてもよろしいですか?」)、明確な承認を待ってください。ハーネス/権限レイヤーによってマージがブロックされる場合、それはガードレールが機能しているということです。その状況を伝えて確認を求め、回避策を探してはいけません。
- 各セッションの開始時と、中断後に、ブランチがまだ存在することを確認してください —
omni models list --model-id <sharedModelId> --include activeBranches。他のユーザーがマージしている可能性があります。その場合、書き込みはBranch does not existエラーで失敗し、ブランチに紐づくドラフトはすでに公開されていることがあります(omni documents list-drafts <identifier>で確認してください)。マージ済みの場合は、ローカルの YAML と共有モデルを比較し、以降の変更用に新しいブランチを作成してください。 - モデル化する前にデータをプロファイリングしてください。 粒度(各ファクトでの
COUNT(*)とCOUNT(DISTINCT <key>)の比較)、暗黙の単位(カテゴリごとに値 ÷ 数量を計算し、「時間」列に金額が格納されていないか確認する)、履歴の開始時点(古いレコードには期首残高が必要な場合があります)を確認してください。曖昧な用語(「手数料タイプ」「ステータス」など)の意味が不明な場合は、推測で進める前に業務オーナーに確認してください。 - 評価用に作成したファイルは、確認が取れるまでブランチに置いてください — 検証用のフィールド/ビューを作成した場合は、ブランチ名/ID、検証ステータス、テストクエリの結果を報告してください。マージについては、上記の重大な停止事項に従ってください。
コマンドの確認
omni models --help # List all model operations
omni models yaml-create --help # Show flags for writing YAML
omni models yaml-create --schema # Print the body's JSON schema + a filled example (no token)
安全な開発ワークフロー
必ずブランチで作業し、本番環境へ直接書き込まないでください。また、まずブランチを作成できるか確認してください。 ブランチの作成にはモデル全体へのアクセス権が必要です。
omni whoami whoami --model-id <modelId>を実行してください。QUERY_FULL_MODELがあればブランチを作成できます(さらにUPDATEもあればマージ/昇格できます。ない場合は PR を開くか、マージを依頼してください)。これらがなければブランチを作成できません。単発のフィールドは、代わりにドキュメントのワークブックモデルに追加してください(omni-content-builder→ ダッシュボードのモデルを更新する)。権限と機能の完全な対応表:omni-admin→ モデルのロールと呼び出し元のアクセス権。
ステップ 0:ブランチを作成する
omni models create-branch <modelId> --name "my-feature-branch"
レスポンスの model.id が branchId です。これは、以降のすべての API 呼び出しに渡す UUID です。既存のブランチはいつでも次のコマンドで一覧表示できます。
omni models list --include activeBranches
⚠️ Git 接続モデル — Git 内のモデル YAML を手動で編集しないでください。 リポジトリはガバナンス(PR、レビュー、監査)のための Omni モデルの投影であり、信頼できる唯一の情報源でも、編集の対象でもありません。Omni は独自の信頼できる状態からデフォルトブランチを再生成し、その状態に含まれない Git のみのモデルファイルを削除します。実際に、Git にのみコミットされたファイルが次の同期時に気づかれないまま消失した顧客インシデントが発生しています。そのため、Omni API を使ってブランチ上で作成し →
omni models commit(ステップ 3)→ Git プロバイダーでレビュー/マージしてください。手動編集したモデル YAML を直接プッシュしないでください。モデルの内容とリポジトリのガバナンス — これが安全性を支える分担です。
- Omni モデルの内容(ビュー/トピック/リレーションシップの YAML):Omni のブランチ上で作成 →
omni models commit→ PR。Git に直接コミットしないでください。Omni がその内容を上書きして再生成します。- リポジトリのガバナンス/モデル以外のファイル(ルートの
omni/OWNERS.yaml、CODEOWNERS、CI 設定、ドキュメント、スクリプト):Omni モデルの内容ではないため、Git に直接コミットしても問題ありません。Omni による再生成で変更されることはありません。
ステップ 1:YAML をブランチに書き込む
omni models yaml-create <modelId> --body '{
"fileName": "my_new_view.view",
"yaml": "dimensions:\n order_id:\n primary_key: true\n status:\n label: Order Status\nmeasures:\n count:\n aggregate_type: count",
"mode": "extension",
"branchId": "{branchId}",
"commitMessage": "Add my_new_view with status dimension and count measure"
}'
注:
branchIdパラメーターには、サーバーから取得した UUID(ステップ 0)を指定する必要があります。代わりに文字列の名前を渡すと、400 Bad Request: Unrecognized key: "branchName"が返されます。
⚠️ 既存ファイルの編集は、正確なパスを指定したファイル全体の読み取り・変更・書き込みです。
yaml-createはファイルの作成者による内容を置き換えます(フィールド単位のマージは行いません)。そのため、先にyaml-getで読み取り、編集してからファイル全体を書き戻してください。そうしないと、ほかの作成者によるフィールドが失われます。fileNameはファイルの正確なパスです(読み取り時とは異なり、正規表現は使えません)。フォルダの接頭辞も含め、完全パスのキーをそのまま再利用してください(例:MARTS/fct_ai_events.view)。名前が一致しなくてもエラーにはならず、そのパスに重複ファイルが黙って作成されます(success: true)。スキーマの基本カラムはスキーマレイヤーにあるため、影響を受けません。ブランチを確認するには、yaml-getを--file-nameなしで実行するとモデル全体が列挙されます。ブランチで変更されたファイル(差分)のみを表示するには--mode extension、完全に構成されたモデル(スキーマ + 共有 + ブランチ)を表示するには--mode combinedを指定します。その後、正確なパスを指定して各ファイルの内容を確認できます。
dbt 接続モデル:
omni models branch-dbt-get <modelId> <branchName>(CLI ≥ 1.1.2)を実行すると、ブランチが参照する dbt 環境と、コンパイル対象の dbt Git ブランチを確認できます。ブランチに独自の環境がない場合は、接続のデフォルト(本番)環境が参照され、is_default_environment: trueと報告されます。
ステップ 2:検証とテスト
すべての YAML の書き込みは、マージ前に検証してテストする必要があります。有効な YAML でも、誤った結果が返されたり、クエリが壊れたりすることがあります。
# 1. Validate — a NEW issue with is_warning:false that references your changed file is blocking; fix before proceeding
omni models validate <modelId> --branch-id <branchId>
# 2. Query the fields you changed — confirm no error, and cache_metadata.num_rows > 0
# (the row count is at cache_metadata.num_rows; there is NO summary.row_count — see omni-query)
omni query run --body '{"query":{"modelId":"<modelId>","table":"your_view","fields":["your_view.new_dimension","your_view.new_measure"],"limit":10,"join_paths_from_topic_name":"your_topic"},"branchId":"<branchId>"}'
# 3. Read it back — confirm the field is present (and not duplicated at a second path)
omni models yaml-get <modelId> --file-name your_view.view --branch-id <branchId>
検証エラーをトリアージしてください。ほとんどはあなたの変更が原因ではありません。 新規または継承したモデルで、処理を妨げる
not foundエラー(テーブル/ビュー/列の欠落)が発生した場合、通常は古いスキーマが原因です。まずスキーマを更新してください(omni models refresh <modelId>)。これによりエラーは解消されます。更新後も継続するnot foundは実際の問題です(接続先に DB へのアクセス権がない、または参照先が実際に壊れているなど)。残ったエラーについては、変更前の状態を基準にする(またはyaml_pathで問題を絞り込む)ようにし、変更したファイルを参照する新しいエラーだけをブロッカーとして扱ってください。既存のエラーは報告し、追及しないでください。
値が正しく見えるかを確認してください(sum が count を返していないか、ブール値が true/false と表示されているかなど)。フィールドが別のビューを参照している場合は、両方のビューのフィールドを含めて、結合が解決されることを確認してください。結合パスのテスト、omni ai job-submit による自然言語での検証、結果チェックリストの全項目、重複ファイルの復旧については、references/validation-and-testing.md を参照してください。
ウィンドウ関数形式の結果列は、モデルフィールドではなくテーブル計算です。 累計、移動平均、期間比較/MoM %、構成比、順位は、クエリごとに結果セット上で計算されます。ここでメジャー/ディメンションとしてではなく、
omni-query→references/table-calculations.mdに従ってテーブル計算(query.calculations[])として作成してください。ウィンドウの対象を結果セット外の行まで広げる必要がある場合に限り、データウェアハウス内のフィールドとしてモデル化してください。
ステップ 3:ブランチをリリースする
重要:リリースする前に、必ずユーザーに確認してください。本番モデルに適用された変更は、簡単には元に戻せません。検証とテスト(ステップ 2)に合格した後に限り、リリースしてください。
モデルが Git に接続されているか確認します(omni models git-get <modelId>)。sshUrl/baseBranch を含む設定があれば Git 接続済みなので パス A(PR を作成/更新)、404/設定なしの場合は Git に接続されていないので パス B(Omni で直接マージ)です。
パス A — Git 接続済み:PR を作成または更新する
ブランチの内容を Git にプッシュします。既存の PR がない場合は新しい Git ブランチと PR を作成し、ある場合は既存の PR を更新します。
omni models commit <modelId> --body '{
"branch_id": "<branchId>",
"commit_message": "Add my_new_view with status dimension and count measure"
}'
返された pr_url をユーザーに提示します。レビュアーが Git ホストで PR をマージすると、次回の同期時に変更が baseBranch に反映されます。オープンのみ、または更新のみの動作を強制する必要がある場合は、omni models commit --help を実行して、任意の body フラグ(allow_branch_exists、require_branch_exists)を確認してください。
パス B — Git に未接続:Omni でマージする
omni models merge-branch <modelId> <branchName>
マージ後 — 新規トピックとビューを確認する(両方のパス)
マージ後、Omni は独自の(正式な)モデル状態からデフォルトブランチを再生成します。正規形式に再シリアライズし、マージされた Git の内容がその状態と異なる場合にのみ正規化コミットを追加します。Omni API 経由で作成された内容はすでに正規形式のため、問題なくマージできた場合、追加コミットは発生しないことがよくあります。コミットを探し回るのではなく、解決結果で確認してください。(Git を使わないマージでは、ブランチが共有モデルに昇格します。)いずれの場合も、特に新規トピックまたはビューについては、ファイルが本番モデルで解決されることを確認してください(--branch-id は指定しません)。
# 1. Files resolve in production — the new view appears / the new topic resolves
omni models get-views <modelId> # new view is listed
omni models get-topic <modelId> <topicName> # new topic resolves (base_view_name + join_via_map present)
# 2. Production model validates — no blocking errors (any is_warning:false is blocking)
omni models validate <modelId>
# 3. Run at least one semantic query against the new topic/view
omni query run --body '{"query":{"modelId":"<modelId>","table":"<base_view>","fields":["<base_view>.<field>"],"limit":10,"join_paths_from_topic_name":"<topicName>"}}'
クエリのレスポンスで、summary.missing_fields が [] であり、summary.invalid_calculations が空であることを確認してください。なお、後者は [] ではなく {} として返されます。missing_fields が空でない場合は、フィールドが解決されていません。これは、マージ中にモデルファイルが削除されたか、名前が変更されたことを示します。欠落がある場合は、Omni 経由で再作成してください。Git で手動で修正して戻してはいけません。
YAML ファイルの種類
| 種類 | 拡張子 | 目的 |
|---|---|---|
| View | .view | テーブルのディメンション、メジャー、フィルター |
| Topic | .topic | ビューを結合してクエリ可能な単位を作成します |
| Relationships | (special) | グローバルな結合定義 |
| Composite topic | .composite_topic | 共通のディメンションを基準に2つ以上のトピックを結合します(composite-topics.mdを参照) |
mode: "extension"(共有モデルレイヤー)を指定して書き込みます。ファイルを削除するには、空のyamlを送信します。
ビューの作成
結合に参加するすべてのビューには、実際の
primary_key: trueディメンションが必要です。 真に行を一意に識別する主キーがない場合、このビューに結合するクエリでファンアウトエラーや誤った集計が発生する可能性があります。テーブルの自然な一意識別子(例:id、order_id、user_id)を使用してください。一意な列が1つもない場合は、たとえばsql: ${order_id} || '-' || ${line_number}のように、行レベルで一意となる複数の列から複合キーを作成してください。行を一意に識別する式を定義できない場合は、まだディメンションにprimary_key: trueを設定しないでください。まず粒度を修正するか、実際のキーができるまでそのビューの結合を避けてください。
PKが仕組み上重要な理由 — 対称集計。 Omniは、主キーで重複を排除することで、1対多の結合でも
sum/count/avgを正しく保ちます(対称集計を参照)。PKがないビューは対称集計にできないため、そのビューの行数を数えるcountメジャーは、結合によって行が重複するたびに過大になります。count_distinctメジャーだけは、仕組み上重複を排除するため正しい値を保ちます。診断の目安: あるメジャーが、本来その部分集合であるはずのメジャーを上回る場合(例:*「商品を閲覧したセッション数」>「セッション総数」)、PKがない/不十分なビューで重複を排除しないカウントがファンアウトしている可能性を疑ってください。数値を取り繕うのではなく、PKを修正してください。すべてのベースビューでPKを確認してください(PKが1つ欠けているだけでも、可視化が1つ壊れる可能性があります)。ダッシュボードのフィルター/コントロールは、フィールドを満たすためにグローバルなrelationshipsグラフ経由で、そのトピックに宣言されていない結合を取り込む場合があります。そのため、「単一トピック」のタイルでもファンアウトが発生する可能性があります。どのような場合でも集計の正しさを保つのがPKの役割です。
基本的なビュー
dimensions:
order_id:
primary_key: true
status:
label: Order Status
created_at:
label: Created Date
measures:
count:
aggregate_type: count
total_revenue:
sql: ${sale_price}
aggregate_type: sum
format: currency_2
スキーマレイヤーと拡張レイヤーについて
ビューを作成すると、Omni はスキーマ(データベース構造)とモデル(ビジネスロジック)を分離します。
- スキーマレイヤー:列ごとに1つ、自動生成される基本ディメンションです。型はデータベースから取得されます。読み取り専用で、スキーマの更新によって同期されます。
- 拡張レイヤー:カスタムの YAML です。基本ディメンションを上書きしたり、新しいディメンションやメジャーを追加したり、列を非表示にしたり、ビジネスロジックを追加したりできます。
同じ名前のフィールドが両方のレイヤーに存在する場合、拡張レイヤーの定義が優先されますが、型情報はスキーマレイヤーから取得されます。
例:テーブルに created_at(DATE)列と revenue(NUMERIC)列があります。
# Schema layer (auto-generated)
dimensions:
created_at: {} # type: DATE, auto-generates timeframes
revenue: {} # type: NUMERIC
# Extension layer (your YAML)
dimensions:
created_at:
label: "Order Created"
description: "When the order was placed"
revenue:
hidden: true # Hide the raw column
measures:
total_revenue:
sql: ${revenue}
aggregate_type: sum
format: currency_2
結果:created_at はスキーマレイヤーから型を継承し(自動で週/月/年の粒度が設定された DATE)、ラベルには指定した値が使われます。元の revenue 列は非表示になり、total_revenue メジャーを通じてのみ公開されます。
重要なポイント:拡張レイヤーでディメンションを定義しても、型情報を提供するスキーマレイヤーの基本ディメンションがなければ、Omni は粒度や型を推論できません。まずスキーマを更新して、スキーマレイヤーを自動生成してください。
記述内容の読み戻し — --mode。 yaml-get は既定で結合済みの結果を返します。つまり、スキーマの基本情報と拡張レイヤーがマージされます。自動生成された基本列を含めず、自分が作成した差分だけを確認するには、--mode extension を指定して読み込みます。
# What you authored (deltas only)
omni models yaml-get <modelId> --file-name your_view.view --branch-id <branchId> --mode extension
# What the model actually resolves to (schema + extension merged) — the default
omni models yaml-get <modelId> --file-name your_view.view --branch-id <branchId> --mode combined
変更した内容を確認するには extension を使い、モデルがどのように解決されるかを確認するには combined を使います。モデルが Git と統合されている場合、結合済みの出力はリポジトリに書き込まれる内容を反映します。そのため、コミットされた *.view.yaml ファイルにはスキーマレイヤーの table_name: と基本列が含まれ、拡張レイヤーには差分のみが含まれます。Git と同期された共有拡張モデルの場合、ファイルに含まれるのは拡張レイヤーのみで、これは --mode extension が返す内容です。その他の --mode の値:staged はブランチモデルのみを返します。merged はブランチモデルと共有モデルをマージしたものを、extension と同じ形式で返します。fully-resolved は extends チェーンを展開した combined を返します(--mode combined --fully-resolved true と同じです)。
ディメンションのパラメーター
35 個以上のディメンションパラメーター、書式の値、期間の一覧については、references/modelParameters.md を参照してください。
最もよく使われるもの:sql、label、description(Blobby でも使用)、primary_key(一意キー。集計に不可欠)、hidden(ピッカーでは非表示になりますが、SQL では使用可能)、format(number_2/currency_2/percent_2/id)、group_label、synonyms(AI マッチング用の別名)。
注意点が2つあります。元の列は名前によって自動的にマッピングされるため、sql: は不要です。また、${TABLE} という構文はありません。${TABLE}.column は検証時またはクエリ実行時に Column "__omni_scoped" not found エラーになります(フィールドは ${field}/${view.field} で参照してください)。
メジャーのパラメーター
references/modelParameters.md(24 個以上のパラメーターと、13 種類すべての集計タイプ)および references/yaml-filter-syntax.md(フィルター演算子とメジャーフィルターの例)を参照してください。フィルター付き集計では、sql 内の CASE WHEN/WHERE よりも、メジャーの filters: ブロックを優先してください。sql は集計対象の値に専念させます。
粒度レベルの集計(ディメンションとメジャーの fixed/always_include/always_exclude)については、references/level-of-detail.md を参照してください。
measures:
completed_revenue:
sql: ${sale_price}
aggregate_type: sum
filters:
status:
is: Complete
フィルター専用フィールドと動的フィールド
ユーザーの選択によって、どの行を残すかではなく、フィールドの計算方法を切り替える場合(作成日または出荷日を基準にレポートする、同じ KPI で売上または注文数を表示する、閲覧者が設定するしきい値を適用するなど)は、フィルター専用フィールドを使います。これはビュー単位の filters: エントリーで、列を持たず、他のフィールドから Mustache 経由で参照します。フィールドの表示/非表示を切り替える用途(トピックの fields: を使います)、行をフィルターする用途(通常のフィルターを使います)、または2つのバリエーションにそれぞれ独立したトピックが適している場合(「新しいトピックと拡張」の項を参照)には、使わないでください。形式、バインド、検証については、templated-filters.md を参照してください。
集計テーブル(集計対応)
集計テーブルを使うのは、テーブルより粗い粒度で同じファクトのロールアップが繰り返しクエリされる場合(日単位または月単位のタイルをイベントレベルのファクトに対してクエリする場合など)で、事前集計テーブルが存在するか、作成できる場合です。ビューに materialized_query ブロックを宣言します。テーブルごとに1つ指定し、ベースビューを基準に記述します。クエリが適合するとOmniはそのテーブルを読み込み、適合しない場合はファクトテーブルにフォールバックします。テーブルにない列が必要なクエリ、別の粒度での非加算的なメジャー(average、count_distinct、median)、またはテーブルより細かい粒度のクエリには役立ちません。 -- Query rewritten to use materialized view で始まる planOnly クエリで確認してください。ウィンドウ関数のフィールド(ROW_NUMBER、RANK、LAG、累計)や *_distinct_on メジャーは絶対にマッピングしないでください。また、materialized_query に limit や offset を設定しないでください。いずれも誤った結果を返すか、Omniがテーブルを使用できなくなります。履歴の一部を保持するテーブルには日付を固定し、ベースビューではすべての行を保持して、モデルのSQLでは日付の境界に >= と < を使用してください。ルール、フィルターの固定、結合ビュー、宣言すべきでないもの、既知の問題については、aggregate-awareness.mdを参照してください。
詳細レベル
level_of_detail を使うのは、メジャーをクエリの粒度とは異なる粒度で計算する必要がある場合です。たとえば、すべての注文行で顧客ごとの合計を表示する場合は(fixed:)、より細かい粒度の集計をまとめる場合は(always_include:)、より細かいディメンションがレポートに含まれていても金額をより粗い粒度に保つ場合は(always_exclude:)を使います。レポートが実際に使用する粒度を指定してください。fixed: は、指定したフィールドがレポートに含まれている場合に限り、リストにないすべての項目に対して一定になります。レポートで使用しないフィールドを指定すると、メジャーが再分割されます。always_exclude は、存在する粗いフィールドに応じて調整され、指定しすぎても問題ありませんが、べき等な外側の集計関数(sum ではなく max)が必要です。always_include でレベルの上限を設定することはできません。また、リストで指定できるのはフィールド参照のみで、ワイルドカードは使えません。明細に繰り返し表示されるヘッダー金額については、リストが不要な unrelated_dimension_handling: repeat を使った複合トピックも検討してください。粒度の一致、外側の集計ルール、テンプレートの再利用、検証については、level-of-detail.mdを参照してください。
ビュー内のクロスビュー・フィールド
グローバルビューファイル内のクロスビュー・フィールド(${other_view.field} を参照する sql を持つディメンションまたはメジャー)は、ホストビューを公開するすべてのトピックで評価されます。グローバルなリレーションシップにより、グローバルな結合グラフを継承するトピックで依存先に到達できる場合がありますが、トピックに明示または固定で指定された joins: マップが上書きされることはありません。そのマップに依存先が含まれていない場合、検証でブロッキング要因となる field_broken_in_topic の問題が返され、そのフィールドを使ったクエリはプランニングに失敗します。
配置場所はフィールドの名前空間ではなく、意図する利用範囲と解決済みの結合コンテキストに基づいて決めます。 そのフィールドが特定のトピックでのみ意味を持つ場合、またはトピック固有、別名付き、あるいは固定された結合に依存する場合は、トピックの views.<host_view> ブロックに定義します(「トピックのスコープに限定したビュー定義」を参照)。フィールドは引き続き <host_view>.<field> としてクエリできます。トピックのスコープが制限するのは利用可能な場所であり、ユーザーが要求する名前空間ではありません。
フィールドがあらゆるトピックで意味を持ち、その依存先がホストビューを公開するすべてのトピックで曖昧さなく解決される場合は、グローバルビューファイルを使用してください。選択する前に、該当するトピックを列挙し、グローバルなリレーションシップファイルだけでなく、各トピックの解決済み get-topic join_via_map を確認してください。そのうえで、ブランチを検証し、結合コンテキストごとに少なくとも1つのトピックでクエリしてください。明示的な結合を持たないトピックはグローバルなリレーションシップを継承できますが、明示的な結合を持つトピックでは除外される場合があります。
フォールバック:yaml-get にビューが表示されない場合
ビューが存在しないと判断する前に、必ず次の2段階の確認を行ってください。yaml-get が返すのは、現在読み込まれているスキーマのビューのみです。オフロード済みまたは非アクティブなスキーマのビューは表示されませんが、引き続き利用できます。
# 1. List all schemas the connection knows about (loaded, offloaded, and inactive)
omni models get-schemas <modelId>
# → {"schemas": ["ANALYTICS", "PUBLIC", "STAGING", ...]}
# 2. If the target schema appears in the list, load it explicitly
omni models yaml-get <modelId> --include-schemas PUBLIC
--include-schemas のルール:
- 1回の呼び出しで指定できるスキーマ名は1つだけです。カンマは使用できません。スキーマは1つずつ読み込んでください。
- 応答にはそのスキーマのビューのみが含まれます。他のスキーマとのリレーションシップは保持されます。
- ブランチを対象にするには、
yaml-getまたはget-schemasに--branch-id <id>を追加してください。
スキーマが get-schemas の一覧にまったくない場合、接続にアクセス権がないか、スキーマが同期されていない可能性があります。接続管理者に確認してください。
トピックの作成
トピックを作成する前に、参照する予定のすべてのビューが実際に存在することを確認してください。
omni models yaml-get <modelId>を実行し、各ビューが表示されることを確認してください。ビューが見つからない場合は、存在しないと判断する前に、上記の遅延読み込みのフォールバックを実行してください。オフロード済みのスキーマにあるだけかもしれません。
新しいトピックを作成するか、既存のトピックを拡張するか
既存のトピックではクエリに回答できない場合、新しいトピックを作成するのではなく、単に既存のトピックを拡張すべきか、まず確認してください。リクエストのベースビュー(FROM)が既存のトピックのベースビューと一致する場合は、通常、拡張するのが適切です。たとえば、必要なビューに到達できるようにリレーションシップ/結合を追加したり、フィールド/ラベルを追加したりします。次のいずれかが根本的に異なる場合は、新しいトピックを作成してください。
- 対象/オブジェクト — 異なるベースビュー(FROM)です。クエリが本質的に記述する対象は何でしょうか。注文ですか、ユーザーですか、それとも時間(日付)ですか。中心となるエンティティが異なる場合は、独自のトピックが必要です。
- 制約 — 常に適用される条件です(たとえば、注文データからテストユーザーを除外する
always_where)。常時適用されるフィルターが異なる場合は、別のトピックにしてください。 - 対象者 — フィールドは同じでも、別の利用者向けにラベル/用語が異なります。対象者によって専門用語が異なる場合は、別のトピックを作成する根拠になります。
判断が難しい場合は、依頼者に確認し、安全な開発ワークフロー(上記を参照)に従ってブランチ上に新しいトピックを作成してください。制限付きのクエリ実行者/閲覧者が結果にアクセスできるようにするには、ベースビューを直接クエリするのではなく、トピックをクエリする必要がある点にも注意してください。
結合、フィールド、ai_context を含む YAML の完全な例については、トピックの設定を参照してください。使用可能なオプションについては、トピックのパラメーターを参照してください。
トピックの主な要素:
base_view— このトピックの主要なビューjoins— 結合チェーンのネストされた構造(例:users: {}またはinventory_items: { products: {} })ai_context— Blobby のフィールドマッピングをガイドします(例:「revenue」を total_revenue にマッピング)default_filters— 削除されない限り、すべてのクエリに適用されますalways_where_sql— SQL 式を使用した削除不可の WHERE フィルター(ユーザーは削除できません)always_where_filters— フィルター指定を使用した削除不可の WHERE フィルター(ユーザーは削除できません)always_having_sql— SQL 式を使用した削除不可の HAVING フィルター。集計後に適用されます(ユーザーは削除できません)always_having_filters— フィルター指定を使用した削除不可の HAVING フィルター。集計後に適用されます(ユーザーは削除できません)fields— フィールドの選定:[order_items.*, users.name, -users.internal_id]
トピックのフィルター式
トピックで default_filters、always_where_filters、または always_having_filters を設定するときは、YAML フィルター条件の構文を使用してください。これはメジャーのフィルターで使われるものと同じ構文です。詳しい説明については、references/yaml-filter-syntax.md を参照してください。
ユースケースに適したフィルター設定が明確でない場合は、Omni AI CLI を使用してドキュメントを検索してください。
omni ai search-omni-docs "how do I configure always_where_filters on a topic in Omni?"
モデルの YAML を作成する前に、対象を絞った質問をして、具体的なフィルタリング要件に合った正確な YAML の例を入手してください。
複合トピック
2 つのファクトにまたがるメジャーを、共通のディメンションはあるものの結合されていない状態で 1 つのクエリに配置する必要がある場合(月別の売上と返品)、または 1 つのファクトを 2 つの条件で扱う場合(今期と前期、作成日ベースと出荷日ベース)は、複合トピックを使います。多重度で判断してください。集計対象のファクトから見て多対一のフィルターテーブルはディメンションなので、結合します。一対多のテーブルは、集計対象の粒度にまとめたクエリビューです。複合トピックが必要なのは、結合されていないファクトがある場合だけです。1 つのトピックに結合を追加すれば質問に答えられる場合や、2 つ目のメジャーが 1 つ目のメジャーのフィルター適用版である場合は、使わないでください。作成方法、2 つの視点を持つ extends パターン、および @ で指定するクエリの形式については、composite-topics.md を参照してください。
リレーションシップの記述
グローバルリレーションシップ
グローバルリレーションシップは共有リレーションシップファイルで定義され、すべてのトピックで使用できます。標準的で再利用可能な結合には、こちらを使います。
- join_from_view: order_items
join_to_view: users
on_sql: ${order_items.user_id} = ${users.id}
relationship_type: many_to_one
join_type: always_left
| 種類 | 使用する場面 |
|---|---|
many_to_one | Orders → Users |
one_to_many | Users → Orders |
one_to_one | Users → User Settings |
many_to_many | Tags ↔ Products(まれ) |
relationship_type を正しく設定すると、ファンアウトや対称集計のエラーを防げます。
トピック単位のリレーションシップ
定義する前に、グローバルリレーションシップファイルを確認してください。 同じ 2 つのビュー間の結合が、どちらかの方向で定義されていないか確認します。同じ
on_sqlなら重複なので、joins:だけを使います。on_sqlが異なる場合は、下記の拡張ビューのパターンを既定とし、暗黙の上書きは避けてください。モデラーに意図を確認してください。
共有モデルにない単発の結合や、同じテーブルを異なる条件で複数回結合する場合は、トピック単位のリレーションシップを使います。
# .topic file
relationships:
- join_from_view: order_items
join_to_view: users
on_sql: ${order_items.user_id} = ${users.id}
relationship_type: many_to_one
join_type: always_left
joins:
users: {}
joinsとrelationshipsの違い:joinsはトピックに含めるビューとその階層を宣言し、relationshipsは結合条件を定義します。グローバルリレーションシップだけを使用するトピックでは、joinsだけが必要です。単発の結合があるトピックでは、両方が必要です。見落としやすい落とし穴 — 両方が必要ですが、
joinsを省略しても検証は通ります。relationshipsのエントリーを追加して、ビューのjoinsエントリーを忘れると、モデルはエラーなしで検証に合格します。しかし、結合したビューのフィールドはトピックに公開されません(それらを参照するクエリや Markdown の結果は空になります)。この点でvalidateを信用しないでください。フィールドが実際に公開されていることをget-topicで確認してください(validation-and-testing.md を参照)。トピックファイルの形式はさまざまです。joins:マップの下にビューを列挙する形式もあれば、トップレベルに<view>: {}エントリーを置く形式もあります。既存ファイルの形式に合わせてください。
拡張ビュー:同じテーブルを複数の方法で結合する
同じテーブルを複数回結合する必要がある場合(例:購入者と販売者としての users)は、join_to_view_as ではなく、拡張ビューパターンを使います。次の 2 つの方法があります。
方法 1 — グローバル(再利用可能): extends:、役割を示す名前、description: を含む独立した .view ファイルを作成します。リレーションシップをグローバルに定義すれば、どのトピックからも他のビューと同じように結合できます。
方法 2 — トピック単位(インライン): トピックの views: ブロックでエイリアスを定義し、同じファイルにそのリレーションシップを記述します。他のトピックでは通常適用されないエイリアスを定義する場合に使います。
両方の方法について、完全な YAML の例は references/topic-scoped-relationships.md を参照してください。
relationship alias duplicates view nameエラーが表示された場合は、このパターンで解決できます。
トピックにスコープされたビューの定義
トピックでは、views: ブロックをインラインで使ってビューを定義または上書きできます。これにより、display_order の制御、label の上書き、トピック固有のフィルター付きメジャーや派生ディメンションの追加、ビューをまたぐフィールドの定義、エイリアスごとの条件を指定した同一ビューの複数の方法での結合が可能です。
既存のビューにトピックにスコープされたフィールドを追加する前に:
- ビューの YAML(
omni models yaml-get)を読み、対象のフィールドがすでに存在しないことを確認してください。同じ定義で存在している場合は、追加を省略してください。- 同じ名前のフィールドが異なる SQL で存在する場合、これは上書きです。必ずモデラーに確認してください。このトピックを介したクエリではトピックにスコープされた定義が使われ、他のすべてのトピックでは共有定義が使われます。
# Example: display order + topic-specific filtered measure
views:
order_items:
display_order: 0
measures:
us_revenue:
sql: ${sale_price}
aggregate_type: sum
format: currency_2
filters:
users.country:
is: US
パターンの全例(ラベルの上書き、派生ディメンション、ビューをまたぐフィールド、複数結合のライフサイクル、トピックにスコープされたクエリビュー)については、references/topic-scoped-views.md を参照してください。
views:ブロック内のビューをまたぐフィールド:${view_name.field_name}参照を記述する前に、参照するすべてのビューがトピックのjoins:ブロックで宣言されていることを確認してください。結合されていないビューへの参照があると、モデルバリデーターがエラーを出します。
同じビューを複数の方法で結合する場合(例:ARR を開始時/現在/終了時の各時点で参照):トピックの views: ブロック内で extends: を使い、名前付きエイリアスを作成します。それぞれのエイリアスには、relationships: 内で独自の on_sql を設定します。各エイリアスはベースビューのすべてのフィールドを継承し、ラベルを個別に上書きできます。完全な YAML の例については、references/topic-scoped-views.md を参照してください。
トピックにスコープされたクエリビュー: クエリビューはトピックの views: ブロック内でも定義でき、そのトピックだけにスコープできます。主キーのルールは同じです(primary_key: true または custom_compound_primary_key_sql)。新しいビューに relationships: エントリーと joins: エントリーを追加してください。クエリビューと、完全な例を掲載した references/topic-scoped-views.md を参照してください。
クエリビュー
保存済みクエリによって定義される仮想テーブルです。クエリビューには主キーが必要です。主キーがないと、結合時にファンアウトエラーが発生します。書き込む前に、各行を一意に識別するフィールドを確認してください。ただし、クエリ自体と関連するビューから主キーを明確に推測できる場合を除きます(例:既知の主キーが user_id である users ビューから user_id を選択するクエリ)。
主キーを定義する方法は2つあります。
オプション1 — 単一の一意なフィールド: dimensions: ブロックで、ディメンションをちょうど1つ primary_key: true に設定します。
オプション2 — 複合キー: 単一のフィールドでは一意にならず、組み合わせで一意になる場合は、ビューのレベルで custom_compound_primary_key_sql: [field_a, field_b] を設定します。primary_key: true のディメンションは必要ありません。
どちらのオプションも、query: ブロック(フィールドをマッピングする仮想テーブル)と sql: ブロック(生の SELECT)のどちらでも使用できます。sql: ブロックでは、ハードコードされた CATALOG.SCHEMA.TABLE パスではなく、${view_name} を使ってビューの基になるテーブルを参照してください。こちらの方法が推奨されており、テーブルを移動しても正しく機能します。各バリエーションの完全な YAML については、references/query-view-examples.md を参照してください。
一意なフィールドがわからない場合は、ビューを書き込む前にユーザーに確認してください。主キーのないクエリビューを結合すると、"Joins fan out the data without a primary key" エラーが発生します。参照先:https://community.omni.co/t/why-am-i-getting-the-error-joins-fan-out-the-data-without-a-primary-key/37
クエリビューを1つのトピックに限定する方法については、トピックに限定したビュー定義を参照してください。
ロールアップにおける sql: と query: の違い。 フィールド参照(${view.field})は sql: ブロック内で使用できますが、Omni はファイルの保存時に一度だけ、エイリアス付きの列名に展開します。そのため、FROM にはビューの参照名をエイリアスとして指定する必要があります(FROM ${order_items} AS "order_items")。検証ではエイリアスの欠落は検出されませんが、クエリの実行時には検出されます。query: 形式(ビューのフィールドとメジャーを列名にマッピングする fields: に加えて、base_view と topic を指定する形式)は、実行のたびにモデルを通じてコンパイルされるため、後からフィールドに加えた変更が反映されます。sql: クエリビューには count メジャーが自動的に追加されないため、必要な場合は宣言してください。例については references/query-view-examples.md を参照してください。
よくある検証エラー
| エラー | 修正方法 |
|---|---|
| "No view X" | ビュー名のスペルを確認します |
| "No join path from X to Y" | リレーションシップを追加します |
| "Duplicate field name" | 重複を削除するか名前を変更します(自動生成されたフィールドの場合は hidden: true で非表示にできます) |
| "Invalid YAML syntax" | インデントを確認します(スペース2つ、タブなし) |
| 結合時のファンアウト/誤った集計 | 結合されるビューに primary_key: true を追加します。結合に関与するすべてのビューに主キーが必要です |
列参照エラー(例:"Column X not found") | テーブルが存在すること、および Omni の接続にアクセス権があることを確認します |
| 編集後にリポジトリのルートに重複したビューが表示された | ファイルの完全なパスではなく、単独の fileName を指定して書き込みました。余分なルートファイルを削除し(空の yaml を送信します)、フォルダーのプレフィックス(例:MARTS/)を含む正確な files キーを使って書き直します |
トラブルシューティング:モデルとデータベースの同期が取れていない
モデルにデータベースの変更が反映されない場合(列/テーブルの欠落、型の誤り、参照の破損など)は、スキーマを更新してから(上記の「スキーマの更新」を参照)、omni models validate <modelId> を実行してください。フィールド名の衝突や列参照の破損は、通常 hidden: true の設定または名前の変更で修正できます(「よくある検証エラー」を参照)。テーブルが継続して見つからない場合、接続にそのデータベース/スキーマへのアクセス権がありません。
ドキュメントリファレンス
- モデル YAML API · ビュー · トピック · ディメンション · メジャー · リレーションシップ · クエリビュー · 複合トピック · テンプレートフィルター · 集計認識 · ブランチモード
関連スキル
- omni-model-explorer — 変更する前にモデルを理解する
- omni-ai-optimizer — トピックの作成後に AI コンテキストを追加する
- omni-query — 新しいフィールドをテストする