omni-model-builder
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOmni Model Builder
Omni 模型构建器
Create and modify Omni's semantic model through the YAML API — views, topics, dimensions, measures, relationships, and query views.
Tip: Always usefirst to understand the existing model.omni-model-explorer
通过YAML API创建和修改Omni的语义模型——包括视图、主题、维度、度量、关系和查询视图。
提示:始终先使用了解现有模型。omni-model-explorer
Prerequisites
前提条件
bash
undefinedbash
undefinedVerify the Omni CLI is installed — if not, ask the user to install it
验证Omni CLI是否已安装——如果未安装,请提示用户安装它
command -v omni >/dev/null || echo "ERROR: Omni CLI is not installed."
```bashcommand -v omni >/dev/null || echo "ERROR: Omni CLI is not installed."
```bashShow available profiles and select the appropriate one
显示可用配置文件并选择合适的配置文件
omni config show
omni config show
If multiple profiles exist, ask the user which to use, then switch:
如果存在多个配置文件,请询问用户使用哪个,然后切换:
omni config use <profile-name>
You need **Modeler** or **Connection Admin** permissions.
> **Tip**: Use `-o json` to force structured output for programmatic parsing, or `-o human` for readable tables. The default is `auto` (human in a TTY, JSON when piped).omni config use <profile-name>
你需要拥有**Modeler(建模者)**或**Connection Admin(连接管理员)**权限。
> **提示**:使用`-o json`强制输出结构化内容以便程序解析,或使用`-o human`输出易读的表格。默认值为`auto`(在终端中输出人类可读格式,管道传输时输出JSON)。Omni's Layered Modeling Architecture
Omni的分层建模架构
Omni uses a layered approach where each layer builds on top of the previous:
- Schema Layer — Auto-generated from your database. Reflects tables, views, columns, and their types. Kept in sync via schema refresh.
- Shared Model Layer — Your governed semantic model. Where you define dimensions, measures, joins, and topics that are reusable across the organization.
- Workbook Model Layer — Ad hoc extensions within individual workbooks. Used for experimental fields before promotion to shared model.
- Branch Layer — Intermediate development layer. Used when working in branches before merging changes to shared model.
Key concept: The schema layer is the foundation and source of truth for table/column structure. When your database schema changes (new tables, deleted columns, type changes), you refresh the schema to keep Omni in sync. All user-created content (dimensions, measures, relationships, topics) flows through the shared model layer.
Development workflow: When building or modifying the model, you work in branches (see "Safe Development Workflow" below). Branches are isolated copies where you can safely experiment before merging changes back to shared model. This skill covers creating and editing model definitions in both branches and shared models.
Omni采用分层方法,每一层都构建在前一层之上:
- Schema层——从数据库自动生成。反映表、视图、列及其类型。通过Schema刷新保持同步。
- 共享模型层——受管控的语义模型。在此定义可在整个组织中复用的维度、度量、关联和主题。
- 工作簿模型层——单个工作簿内的临时扩展。用于在推广到共享模型之前试验字段。
- 分支层——中间开发层。用于在分支中工作,之后再将变更合并到共享模型。
核心概念:Schema层是表/列结构的基础和事实来源。当数据库Schema发生变化(新增表、删除列、类型变更)时,你需要刷新Schema以保持Omni同步。所有用户创建的内容(维度、度量、关系、主题)都通过共享模型层流转。
开发工作流:构建或修改模型时,你需要在分支中工作(见下文“安全开发工作流”)。分支是独立的副本,你可以在其中安全试验,之后再将变更合并回共享模型。本技能涵盖在分支和共享模型中创建和编辑模型定义。
Determine SQL Dialect
确定SQL方言
Before writing any SQL expressions, confirm the dialect from the connection — don't guess from the connection name:
bash
undefined在编写任何SQL表达式之前,从连接中确认方言——不要从连接名称猜测:
bash
undefined1. List models to find connectionId
1. 列出模型以找到connectionId
omni models list
omni models list
2. Look up the connection's dialect
2. 查询连接的方言
omni connections list
omni connections list
→ find your connectionId and read the "dialect" field
→ 找到你的connectionId并查看"dialect"字段
→ e.g. "bigquery", "postgres", "snowflake", "databricks"
→ 例如:"bigquery", "postgres", "snowflake", "databricks"
Use dialect-appropriate functions in your SQL (e.g. `SAFE_DIVIDE` for BigQuery, `NULLIF(a/b)` for Postgres/Snowflake).
使用适合方言的SQL函数(例如BigQuery使用`SAFE_DIVIDE`,Postgres/Snowflake使用`NULLIF(a/b)`)。Schema Refresh: Syncing with Database Changes
Schema刷新:与数据库变更同步
The schema layer is auto-generated from your database. When your database schema changes (new/deleted/renamed columns, type changes), refresh Omni's schema layer to stay in sync.
When to trigger:
- New tables added to your database
- Column added, renamed, or deleted in an existing table
- Creating a new view from scratch and you want auto-generated base dimensions
- Model is out of sync with the database
What it does: Introspects your data warehouse, auto-generates base dimensions with correct types and timeframes, detects deletions and broken references. Runs as a background job (can take several minutes).
Side effect: May auto-generate dimensions for columns you don't need. Suppress with in your extension layer.
hidden: trueTrigger via API:
bash
omni models refresh <modelId>Schema层从数据库自动生成。当数据库Schema发生变化(新增/删除/重命名列、类型变更)时,刷新Omni的Schema层以保持同步。
触发时机:
- 数据库中新增表
- 现有表中新增、重命名或删除列
- 从头创建新视图并希望自动生成基础维度
- 模型与数据库不同步
作用:探查数据仓库,自动生成带有正确类型和时间范围的基础维度,检测删除和无效引用。作为后台任务运行(可能需要几分钟)。
副作用:可能会为你不需要的列自动生成维度。可在扩展层中使用隐藏这些维度。
hidden: true通过API触发:
bash
omni models refresh <modelId>With branch:
指定分支:
omni models refresh <modelId> --branch-id <branchId>
Requires **Connection Admin** permissions.omni models refresh <modelId> --branch-id <branchId>
需要**Connection Admin**权限。Discovering Commands
发现命令
bash
omni models --help # List all model operations
omni models yaml-create --help # Show flags for writing YAMLbash
omni models --help # 列出所有模型操作
omni models yaml-create --help # 显示编写YAML的参数Safe Development Workflow
安全开发工作流
Always work in a branch. Never write directly to production.
始终在分支中工作。切勿直接写入生产环境。
Step 0: Create a Branch
步骤0:创建分支
bash
omni models create-branch <modelId> --name "my-feature-branch"The response is your — a UUID you'll pass to all subsequent API calls. To list existing branches at any time:
model.idbranchIdbash
omni models list --include activeBranchesGit-connected models: If your model is connected to a git repo (returns anomni models git-get <modelId>), merging an Omni branch will automatically commit the changes back to your gitsshUrl. Choose one workflow and stick to it — either edit via the Omni branch API (thenbaseBranchto sync local files), or edit local files and push via git. Mixing both leads to conflicts.git pull
bash
omni models create-branch <modelId> --name "my-feature-branch"响应中的是你的——一个UUID,你需要在后续所有API调用中传递它。随时列出现有分支:
model.idbranchIdbash
omni models list --include activeBranches关联Git的模型:如果你的模型关联了Git仓库(返回omni models git-get <modelId>),合并Omni分支会自动将变更提交回你的GitsshUrl。选择一种工作流并坚持使用——要么通过Omni分支API编辑(然后baseBranch同步本地文件),要么编辑本地文件并通过Git推送。混合使用两种方式会导致冲突。git pull
Step 1: Write YAML to a Branch
步骤1:将YAML写入分支
bash
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"
}'Note: Theparameter must be a UUID from the server (Step 0). Passing a string name instead will returnbranchId.400 Bad Request: Unrecognized key: "branchName"
bash
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"
}'注意:参数必须是来自服务器的UUID(步骤0)。传递字符串名称会返回branchId。400 Bad Request: Unrecognized key: "branchName"
Step 2: Validate and Test
步骤2:验证和测试
Every YAML write must be validated and tested before merging. Silent failures are common — a field can be syntactically valid YAML but produce wrong results or broken queries.
2a. Run model validation:
bash
omni models validate <modelId> --branchid <branchId>Check the response:
- If any issue has , it's an error — fix before proceeding
is_warning: false - Common errors: broken column references, duplicate field names, invalid SQL syntax, missing join paths
- If is present, review the suggestion before applying
auto_fix
2b. Test new/modified fields with a query:
Run a query that exercises the fields you just created or modified:
bash
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>"
}'Two complementary validation tools:
— structured validation using explicit field expressions; use to precisely test specific dimensions, measures, and join pathsomni query run — natural language validation; use to confirm the topic answers business questions correctly against live branch data.omni ai job-submit --branch-id <branchId> --topic-name <topicName>does not resolve branch-only topics at execution time and should not be used for branch validation.omni ai generate-query --run-query true
What to check:
- No error in response — if the query returns an error, the field SQL is broken (bad column reference, wrong aggregate, dialect mismatch)
- > 0 — confirms the field resolves to actual data
summary.row_count - Values look correct — spot-check that a isn't returning a
sum, that a boolean dimension returns true/false (not 0/1 unexpectedly), etc.count - Joins work — if your field references another view (e.g., ), include fields from both views to confirm the join resolves
${users.id}
2c. If you modified a relationship or topic join, test the join path:
bash
omni query run --body '{
"query": {
"modelId": "<modelId>",
"table": "base_view",
"fields": ["base_view.id", "joined_view.some_field"],
"limit": 10,
"join_paths_from_topic_name": "your_topic"
}
}'A working join returns rows with data from both views. A broken join returns an error or null values in the joined columns.
2d. Verify the field appears in the model:
bash
undefined每次写入YAML后必须进行验证和测试。静默失败很常见——字段在语法上是有效的YAML,但可能产生错误结果或无效查询。
2a. 运行模型验证:
bash
omni models validate <modelId> --branchid <branchId>检查响应:
- 如果任何问题的,则为错误——修复后再继续
is_warning: false - 常见错误:无效列引用、重复字段名、SQL语法错误、缺失关联路径
- 如果存在,在应用前查看建议
auto_fix
2b. 通过查询测试新增/修改的字段:
运行查询来测试你刚刚创建或修改的字段:
bash
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>"
}'两种互补的验证工具:
——使用显式字段表达式进行结构化验证;用于精确测试特定维度、度量和关联路径omni query run ——自然语言验证;用于确认主题针对分支实时数据正确回答业务问题。omni ai job-submit --branch-id <branchId> --topic-name <topicName>在执行时无法解析仅分支存在的主题,不应用于分支验证。omni ai generate-query --run-query true
检查要点:
- 响应中无错误——如果查询返回错误,说明字段SQL存在问题(无效列引用、错误聚合、方言不匹配)
- > 0——确认字段解析到实际数据
summary.row_count - 值看起来正确——抽查是否返回
sum,布尔维度是否返回true/false(而非意外的0/1)等count - 关联正常工作——如果字段引用了另一个视图(例如),包含两个视图的字段以确认关联已解析
${users.id}
2c. 如果修改了关系或主题关联,测试关联路径:
bash
omni query run --body '{
"query": {
"modelId": "<modelId>",
"table": "base_view",
"fields": ["base_view.id", "joined_view.some_field"],
"limit": 10,
"join_paths_from_topic_name": "your_topic"
}
}'正常工作的关联会返回包含两个视图数据的行。无效关联会返回错误或关联列中的空值。
2d. 验证字段是否出现在模型中:
bash
undefinedCheck the topic to confirm new fields are listed
检查主题以确认新增字段已列出
omni models get-topic <modelId> <topicName> --branch-id <branchId>
omni models get-topic <modelId> <topicName> --branch-id <branchId>
Or read back the YAML you just wrote
或者读取你刚刚写入的YAML
omni models yaml-get <modelId> --filename your_view.view --branchid <branchId>
Confirm your new fields are listed in the response. If they're missing, the YAML write may have silently failed (e.g., wrong `fileName`, malformed YAML string) — or the view may live in an offloaded schema that `yaml-get` doesn't surface. Before concluding a view doesn't exist, run the lazy-load fallback (see "Fallback: View Missing from yaml-get" below).omni models yaml-get <modelId> --filename your_view.view --branchid <branchId>
确认你的新字段已在响应中列出。如果缺失,YAML写入可能已静默失败(例如错误的`fileName`、格式错误的YAML字符串)——或者视图可能位于`yaml-get`无法显示的卸载Schema中。在得出视图不存在的结论之前,运行懒加载回退(见下文“回退:yaml-get无法找到视图”)。Step 3: Merge the Branch
步骤3:合并分支
Important: Always ask the user for confirmation before merging. Merging applies changes to the production model and cannot be easily undone. Only merge after validation and testing pass (Step 2).
bash
omni models merge-branch <modelId> <branchName>If git with required PRs is configured, merge through your git workflow instead.
After merging, run one final validation against the production model to confirm the merge didn't introduce conflicts:
bash
omni models validate <modelId>重要提示:合并前务必征得用户确认。合并会将变更应用到生产模型,且无法轻易撤销。仅在验证和测试通过(步骤2)后进行合并。
bash
omni models merge-branch <modelId> <branchName>如果配置了需要PR的Git,请通过Git工作流进行合并。
合并后,针对生产模型运行最终验证以确认合并未引入冲突:
bash
omni models validate <modelId>YAML File Types
YAML文件类型
| Type | Extension | Purpose |
|---|---|---|
| View | | Dimensions, measures, filters for a table |
| Topic | | Joins views into a queryable unit |
| Relationships | (special) | Global join definitions |
Write with (shared model layer). To delete a file, send empty .
mode: "extension"yaml| 类型 | 扩展名 | 用途 |
|---|---|---|
| 视图 | | 表的维度、度量、过滤器 |
| 主题 | | 将视图关联为可查询单元 |
| 关系 | (特殊) | 全局关联定义 |
使用(共享模型层)进行编写。要删除文件,发送空的。
mode: "extension"yamlWriting Views
编写视图
Every view that participates in joins MUST have a realdimension. Without a genuine row-unique primary key, queries that join to this view can produce fanout errors or incorrect aggregations. Use the table's natural unique identifier (e.g.,primary_key: true,id,order_id). If no single column is unique, build a composite key from row-level columns that are jointly unique, for exampleuser_id. If you cannot define a row-unique expression, do not mark a dimension assql: ${order_id} || '-' || ${line_number}yet; fix the grain first or avoid joining the view until a real key exists.primary_key: true
所有参与关联的视图必须有真实的维度。 没有真正的行唯一主键,关联到此视图的查询可能会产生扇出错误或不正确的聚合。使用表的自然唯一标识符(例如primary_key: true、id、order_id)。如果没有单个列是唯一的,从行级列构建联合唯一的复合键,例如user_id。如果无法定义行唯一表达式,请不要将维度标记为sql: ${order_id} || '-' || ${line_number};先修复粒度,或者在存在真实键之前避免关联该视图。primary_key: true
Basic View
基础视图
yaml
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_2yaml
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_2Understanding Schema Layer vs Extension Layer
理解Schema层与扩展层
When you create a view, Omni separates schema (database structure) from model (your business logic):
- Schema layer: Auto-generated base dimensions, one per column. Types come from the database. Read-only, synced via schema refresh.
- Extension layer: Your custom YAML. Can override base dimensions, add new dimensions/measures, hide columns, add business logic.
When both layers exist for a field with the same name, your extension definition wins but type information comes from the schema layer.
Example: Table has columns (DATE) and (NUMERIC).
created_atrevenueyaml
undefined创建视图时,Omni将Schema(数据库结构)与模型(你的业务逻辑)分离:
- Schema层:自动生成的基础维度,每列一个。类型来自数据库。只读,通过Schema刷新同步。
- 扩展层:你的自定义YAML。可以覆盖基础维度、添加新维度/度量、隐藏列、添加业务逻辑。
当同一字段名同时存在于两层时,你的扩展定义优先,但类型信息来自Schema层。
示例:表包含(DATE)和(NUMERIC)列。
created_atrevenueyaml
undefinedSchema layer (auto-generated)
Schema层(自动生成)
dimensions:
created_at: {} # type: DATE, auto-generates timeframes
revenue: {} # type: NUMERIC
dimensions:
created_at: {} # 类型:DATE,自动生成时间范围
revenue: {} # 类型:NUMERIC
Extension layer (your YAML)
扩展层(你的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
Result: `created_at` inherits its type from the schema layer (DATE with automatic week/month/year granularities) but gets your label. The raw `revenue` column is hidden, only exposed through the `total_revenue` measure.
**Key insight**: If your extension defines a dimension but there's no schema layer base dimension to provide type information, Omni can't infer granularities or types. Trigger a schema refresh to auto-generate the schema layer first.dimensions:
created_at:
label: "Order Created"
description: "When the order was placed"
revenue:
hidden: true # 隐藏原始列
measures:
total_revenue:
sql: ${revenue}
aggregate_type: sum
format: currency_2
结果:`created_at`从Schema层继承类型(带有自动周/月/年粒度的DATE),但使用你设置的标签。原始`revenue`列被隐藏,仅通过`total_revenue`度量暴露。
**核心要点**:如果你的扩展定义了维度,但没有Schema层的基础维度提供类型信息,Omni无法推断粒度或类型。先触发Schema刷新以自动生成Schema层。Dimension Parameters
维度参数
See for the complete list of 35+ dimension parameters, format values, and timeframes.
references/modelParameters.mdMost common parameters:
- — SQL expression using
sqlreferences${field_name} - — display name ·
label— help text (also used by Blobby)description - — unique key (critical for aggregations)
primary_key: true - — hides from picker, still usable in SQL
hidden: true - —
format,number_2,currency_2,percent_2id - — groups fields in the picker
group_label - — alternative names for AI matching (e.g.,
synonyms)[client, account, buyer]
查看获取35+维度参数、格式值和时间范围的完整列表。
references/modelParameters.md最常用的参数:
- ——使用
sql引用的SQL表达式${field_name} - ——显示名称 ·
label——帮助文本(也用于Blobby)description - ——唯一键(对聚合至关重要)
primary_key: true - ——从选择器中隐藏,但仍可在SQL中使用
hidden: true - ——
format,number_2,currency_2,percent_2id - ——在选择器中分组字段
group_label - ——AI匹配的替代名称(例如
synonyms)[client, account, buyer]
Measure Parameters
度量参数
See for the complete list of 24+ measure parameters and all 13 aggregate types.
references/modelParameters.mdMeasure filters restrict rows before aggregation using the YAML filter condition syntax. See for the complete operator reference and measure filter examples.
references/yaml-filter-syntax.md查看获取24+度量参数和所有13种聚合类型的完整列表。
references/modelParameters.md度量过滤器使用YAML过滤器条件语法在聚合前限制行。查看获取完整的操作符参考和度量过滤器示例。
references/yaml-filter-syntax.mdCross-View Fields in Views
视图中的跨视图字段
Avoid defining cross-view fields (dimensions or measures whose references ) directly in a view file. These fields depend on another view being joined, which is not guaranteed in every topic that includes this view. In topics where the referenced view isn't present, the field will be omitted — but more importantly, the model validator will throw errors for any topic that includes this view without also joining the referenced view. This can create a cascade of validator errors across topics that are otherwise valid but happen to include only a subset of the involved views.
sql${other_view.field}In the vast majority of cases, cross-view fields should be defined in the topic's block (see "Topic-Scoped View Definitions"), where the join context is explicit and controlled.
views:Only define a cross-view field in the view file itself when you are certain the referenced view will always be joined in every topic that includes this view — for example, when the join is defined globally and the two views are inseparable by design.
避免在视图文件中直接定义跨视图字段(引用的维度或度量)。这些字段依赖于另一个视图被关联,但并非所有包含此视图的主题都会保证关联该视图。在未引用视图的主题中,字段会被省略——更重要的是,模型验证器会对任何包含此视图但未关联引用视图的主题抛出错误。这可能会在原本有效的主题中引发一系列验证器错误,只因这些主题包含了相关视图的子集。
sql${other_view.field}在绝大多数情况下,跨视图字段应定义在主题的块中(见“主题范围的视图定义”),此处关联上下文是明确且可控的。
views:仅当你确定引用视图会始终关联到包含此视图的每个主题时,才在视图文件中定义跨视图字段——例如,当关联是全局定义的,且两个视图在设计上不可分离时。
Fallback: View Missing from yaml-get
回退:yaml-get无法找到视图
Before concluding that a view doesn't exist, always run this two-step check. only returns views from currently-loaded schemas — views in offloaded or inactive schemas won't appear, but they're still available.
yaml-getbash
undefined在得出视图不存在的结论之前,始终运行此两步检查。仅返回当前加载的Schema中的视图——位于卸载或非活动Schema中的视图不会显示,但它们仍然可用。
yaml-getbash
undefined1. List all schemas the connection knows about (loaded, offloaded, and inactive)
1. 列出连接知晓的所有Schema(已加载、已卸载和非活动)
omni models get-schemas <modelId>
omni models get-schemas <modelId>
→ {"schemas": ["ANALYTICS", "PUBLIC", "STAGING", ...]}
→ {"schemas": ["ANALYTICS", "PUBLIC", "STAGING", ...]}
2. If the target schema appears in the list, load it explicitly
2. 如果目标Schema在列表中,显式加载它
omni models yaml-get <modelId> --includeschemas PUBLIC
**Rules for `--includeschemas`:**
- Accepts exactly **one schema name** per call — commas are rejected. Load schemas one at a time.
- The response will contain only views from that schema; relationships to other schemas are preserved.
- To scope to a branch, add `--branchid <id>` to `yaml-get` or `--branch-id <id>` to `get-schemas` (flag names differ per command).
If the schema isn't in the `get-schemas` list at all, the connection likely doesn't have access or the schema isn't synced — check with a Connection Admin.omni models yaml-get <modelId> --includeschemas PUBLIC
**`--includeschemas`规则**:
- 每次调用仅接受**一个Schema名称**——逗号会被拒绝。一次加载一个Schema。
- 响应将仅包含该Schema中的视图;与其他Schema的关系会保留。
- 要限定到分支,在`yaml-get`中添加`--branchid <id>`,或在`get-schemas`中添加`--branch-id <id>`(不同命令的参数名称不同)。
如果Schema不在`get-schemas`列表中,连接可能没有访问权限或Schema未同步——请联系Connection Admin检查。Writing Topics
编写主题
Before writing a topic, verify all views you plan to reference actually exist. Runand confirm each view appears. If a view is missing, run the lazy-load fallback above before concluding it doesn't exist — it may simply be in an offloaded schema.omni models yaml-get <modelId>
See Topics setup for complete YAML examples with joins, fields, and ai_context, and Topic parameters for all available options.
Key topic elements:
- — the primary view for this topic
base_view - — nested structure for join chains (e.g.,
joinsorusers: {})inventory_items: { products: {} } - — guides Blobby's field mapping (e.g., "Map 'revenue' → total_revenue")
ai_context - — applied to all queries unless removed
default_filters - — non-removable WHERE filter using a SQL expression (cannot be removed by users)
always_where_sql - — non-removable WHERE filter using filter specifications (cannot be removed by users)
always_where_filters - — non-removable HAVING filter using a SQL expression, applied after aggregation (cannot be removed by users)
always_having_sql - — non-removable HAVING filter using filter specifications, applied after aggregation (cannot be removed by users)
always_having_filters - — field curation:
fields[order_items.*, users.name, -users.internal_id]
编写主题前,验证你计划引用的所有视图确实存在。 运行并确认每个视图都已显示。如果视图缺失,在得出视图不存在的结论之前运行上述懒加载回退——它可能只是位于卸载的Schema中。omni models yaml-get <modelId>
主题核心元素:
- ——此主题的主视图
base_view - ——关联链的嵌套结构(例如
joins或users: {})inventory_items: { products: {} } - ——指导Blobby的字段映射(例如“Map 'revenue' → total_revenue”)
ai_context - ——应用于所有查询,除非被移除
default_filters - ——不可移除的WHERE过滤器,使用SQL表达式(用户无法移除)
always_where_sql - ——不可移除的WHERE过滤器,使用过滤器规范(用户无法移除)
always_where_filters - ——不可移除的HAVING过滤器,使用SQL表达式,在聚合后应用(用户无法移除)
always_having_sql - ——不可移除的HAVING过滤器,使用过滤器规范,在聚合后应用(用户无法移除)
always_having_filters - ——字段整理:
fields[order_items.*, users.name, -users.internal_id]
Filter Expressions for Topics
主题的过滤器表达式
When configuring , , or on a topic, use the YAML filter condition syntax — the same syntax used in measure filters. See for the complete reference.
default_filtersalways_where_filtersalways_having_filtersreferences/yaml-filter-syntax.mdIf the right filter configuration for a given use case isn't obvious, use the Omni AI CLI to search the docs:
bash
omni ai search-omni-docs "how do I configure always_where_filters on a topic in Omni?"Use targeted questions to get precise YAML examples for your specific filtering need before writing the model YAML.
在主题上配置、或时,使用YAML过滤器条件语法——与度量过滤器使用的语法相同。查看获取完整参考。
default_filtersalways_where_filtersalways_having_filtersreferences/yaml-filter-syntax.md如果特定用例的正确过滤器配置不明确,使用Omni AI CLI搜索文档:
bash
omni ai search-omni-docs "how do I configure always_where_filters on a topic in Omni?"在编写模型YAML之前,使用针对性问题获取适合你特定过滤需求的精确YAML示例。
Writing Relationships
编写关系
Global Relationships
全局关系
Global relationships are defined in the shared relationships file and are available across all topics. Use these for standard, reusable joins.
yaml
- 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| Type | When to Use |
|---|---|
| Orders → Users |
| Users → Orders |
| Users → User Settings |
| Tags ↔ Products (rare) |
Getting right prevents fanout and symmetric aggregate errors.
relationship_type全局关系定义在共享关系文件中,可在所有主题中使用。用于标准、可复用的关联。
yaml
- 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| 类型 | 使用场景 |
|---|---|
| 订单 → 用户 |
| 用户 → 订单 |
| 用户 → 用户设置 |
| 标签 ↔ 产品(罕见) |
正确设置可防止扇出和对称聚合错误。
relationship_typeTopic-Scoped Relationships
主题范围的关系
Before defining, check the global relationships file for a join between the same two views in either direction. Same→ redundant, useon_sqlonly. Differentjoins:→ default to the extended views pattern below rather than a silent override. Confirm intent with the modeler.on_sql
Use topic-scoped relationships for one-off joins not in the shared model, or joining the same table multiple times under different conditions.
yaml
undefined定义前,检查全局关系文件是否存在同一两个视图之间的关联(任一方向)。相同的→冗余,仅使用on_sql。不同的joins:→默认使用下文的扩展视图模式,而非静默覆盖。与建模者确认意图。on_sql
主题范围的关系用于共享模型中未包含的一次性关联,或在不同条件下多次关联同一表。
yaml
undefined.topic file
.topic文件
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` vs `relationships`:** `joins` declares which views are in the topic and their hierarchy; `relationships` defines the join conditions. A topic using only global relationships needs only `joins`. A topic with a one-off join needs both.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` vs `relationships`:** `joins`声明主题中包含的视图及其层级;`relationships`定义关联条件。仅使用全局关系的主题只需`joins`。包含一次性关联的主题需要同时使用两者。Extended Views: Joining the Same Table Multiple Ways
扩展视图:多次关联同一表
When the same table needs multiple joins (e.g., as buyer and seller), use the extended views pattern — not . Two variants:
usersjoin_to_view_asVariant 1 — Global (reusable): Create a standalone file with , a role-descriptive name, and a . Define the relationship globally — any topic can then join it like any other view.
.viewextends:description:Variant 2 — Topic-scoped (inline): Define the alias in the topic's block with its relationship in the same file. Use when the alias is not generally applicable in other topics.
views:See for full YAML examples of both variants.
references/topic-scoped-relationships.mdIf you see aerror, this pattern is the fix.relationship alias duplicates view name
当需要多次关联同一表时(例如作为买家和卖家),使用扩展视图模式——而非。两种变体:
usersjoin_to_view_as变体1——全局(可复用): 创建独立的文件,使用、角色描述性名称和。全局定义关系——任何主题都可以像关联其他视图一样关联它。
.viewextends:description:变体2——主题范围(内联): 在主题的块中定义别名,并在同一文件中定义其关系。当别名不适用于其他主题时使用。
views:查看获取两种变体的完整YAML示例。
references/topic-scoped-relationships.md如果看到错误,此模式可解决问题。relationship alias duplicates view name
Topic-Scoped View Definitions
主题范围的视图定义
Topics can define or override views inline using a block — controlling , overriding , adding topic-specific filtered measures or derived dimensions, defining cross-view fields, and joining the same view multiple ways with per-alias conditions.
views:display_orderlabelBefore adding any topic-scoped field to an existing view:
- Read the view YAML (
) and confirm the field doesn't already exist. If it does with the same definition, skip it.omni models yaml-get- If a field with the same name exists but uses different SQL, this is an override. Confirm explicitly with the modeler — queries through this topic will use the topic-scoped definition; all other topics keep the shared one.
yaml
undefined主题可以使用块内联定义或覆盖视图——控制、覆盖、添加主题特定的过滤度量或派生维度、定义跨视图字段,以及使用每个别名的条件多次关联同一视图。
views:display_orderlabel在现有视图中添加任何主题范围的字段前:
- 读取视图YAML(
)并确认字段不存在。如果存在且定义相同,跳过。omni models yaml-get- 如果存在同名字段但使用不同SQL,这是覆盖操作。与建模者明确确认——通过此主题的查询将使用主题范围的定义;所有其他主题保留共享定义。
yaml
undefinedExample: 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
See `references/topic-scoped-views.md` for a full pattern gallery (label overrides, derived dimensions, cross-view fields, multi-join lifecycle, topic-scoped query views).
> **Cross-view fields in `views:` blocks:** Before writing `${view_name.field_name}` references, confirm every referenced view is declared in the topic's `joins:` block — the model validator throws errors for any reference to a view that isn't joined.
**Joining the same view multiple ways** (e.g., ARR at Start / Current / End): Use `extends:` inside the topic's `views:` block to create named aliases, each with its own `on_sql` in `relationships:`. Each alias inherits all base view fields and can override labels independently. For a full YAML example, see `references/topic-scoped-views.md`.
**Topic-scoped query views:** A query view can also be defined inside a topic's `views:` block, scoping it to that topic only. Same primary key rules apply (`primary_key: true` or `custom_compound_primary_key_sql`). Include a `relationships:` entry and a `joins:` entry for the new view — see Query Views section above, and `references/topic-scoped-views.md` for a complete example.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`获取完整示例。Query Views
查询视图
Virtual tables defined by a saved query. A query view must have a primary key or it cannot be joined without producing fanout errors. Before writing, confirm which field uniquely identifies each row — unless the primary key can be clearly inferred from the query itself and the involved views (e.g. a query that selects from a view where is the known primary key).
user_idusersuser_idThere are two ways to define the primary key:
Option 1 — Single unique field: Mark exactly one dimension in the block.
primary_key: truedimensions:Option 2 — Compound key: When no single field is unique but a combination is, set at the view level — no dimension needed.
custom_compound_primary_key_sql: [field_a, field_b]primary_key: trueBoth options work with either a block (field-mapped virtual table) or a block (raw SELECT). In blocks, use to reference a view's underlying table rather than a hard-coded path — it's preferred and stays correct if the table moves. See for complete YAML for each variant.
query:sql:sql:${view_name}CATALOG.SCHEMA.TABLEreferences/query-view-examples.mdIf the user is unsure which field is unique, ask before writing the view. A query view without a primary key will trigger a "Joins fan out the data without a primary key" error when joined. See: https://community.omni.co/t/why-am-i-getting-the-error-joins-fan-out-the-data-without-a-primary-key/37
Query views can also be defined inline within a topic's block, scoping the virtual table to that topic only. See for an example.
views:references/topic-scoped-views.md由保存的查询定义的虚拟表。查询视图必须有主键,否则关联时会产生扇出错误。编写前,确认哪个字段唯一标识每行——除非主键可以从查询本身和涉及的视图中明确推断(例如从视图中选择的查询,其中是已知主键)。
usersuser_iduser_id有两种定义主键的方式:
选项1——单个唯一字段: 在块中将恰好一个维度标记为。
dimensions:primary_key: true选项2——复合键: 当没有单个字段唯一但组合字段唯一时,在视图级别设置——无需维度。
custom_compound_primary_key_sql: [field_a, field_b]primary_key: true两种方式都适用于块(字段映射的虚拟表)或块(原始SELECT)。在块中,使用引用视图的底层表,而非硬编码的路径——这是首选方式,且当表移动时仍保持正确。查看获取每种变体的完整YAML。
query:sql:sql:${view_name}CATALOG.SCHEMA.TABLEreferences/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
查询视图也可以内联定义在主题的块中,将虚拟表限定到该主题。示例见。
views:references/topic-scoped-views.mdCommon Validation Errors
常见验证错误
| Error | Fix |
|---|---|
| "No view X" | Check view name spelling |
| "No join path from X to Y" | Add a relationship |
| "Duplicate field name" | Remove duplicate or rename (or suppress with |
| "Invalid YAML syntax" | Check indentation (2 spaces, no tabs) |
| Fanout / incorrect aggregations on joins | Add |
Column reference error (e.g., "Column | Check that the table exists and your Omni connection has access |
| 错误 | 修复方法 |
|---|---|
| "No view X" | 检查视图名称拼写 |
| "No join path from X to Y" | 添加关系 |
| "Duplicate field name" | 删除重复项或重命名(如果一个是自动生成的,可使用 |
| "Invalid YAML syntax" | 检查缩进(2个空格,不要用制表符) |
| 关联时出现扇出/不正确聚合 | 为关联的视图添加 |
列引用错误(例如"Column | 检查表是否存在,且你的Omni连接有访问权限 |
Troubleshooting: Model Out of Sync with Database
故障排除:模型与数据库不同步
If your model doesn't reflect the database (missing columns, broken references, wrong types), trigger a schema refresh (see "Schema Refresh" section above). Then validate:
bash
omni models validate <modelId>Common issues and fixes:
| Issue | Cause | Fix |
|---|---|---|
| Broken column references | Column no longer exists in database | Remove or update the |
| Field name collision | Auto-generated dimension conflicts with your measure | Suppress with |
| Unknown field types | Type info not available from schema | Verify column exists and connection has access |
| Missing tables | Table not in schema after refresh | Verify table exists and connection includes its database/schema |
如果你的模型未反映数据库(缺失列、无效引用、错误类型),触发Schema刷新(见上文“Schema刷新”部分)。然后验证:
bash
omni models validate <modelId>常见问题及修复方法:
| 问题 | 原因 | 修复方法 |
|---|---|---|
| 无效列引用 | 列在数据库中已不存在 | 删除或更新 |
| 字段名称冲突 | 自动生成的维度与你的度量冲突 | 使用 |
| 未知字段类型 | Schema未提供类型信息 | 验证列存在且连接有访问权限 |
| 缺失表 | 刷新后表不在Schema中 | 验证表存在且连接包含其数据库/Schema |
Docs Reference
文档参考
- Model YAML API · Views · Topics · Dimensions · Measures · Relationships · Query Views · Branch Mode
- Model YAML API · Views · Topics · Dimensions · Measures · Relationships · Query Views · Branch Mode
Related Skills
相关技能
- omni-model-explorer — understand the model before modifying
- omni-ai-optimizer — add AI context after building topics
- omni-query — test new fields
- omni-model-explorer——修改前了解模型
- omni-ai-optimizer——构建主题后添加AI上下文
- omni-query——测试新字段