返回

同一张表,不同营收:Apache Ossie 与 Snowflake 语义层如何定义指标

RSS Snowflake Engineering (Medium) AI 逐段翻译 发布 2026-11-12 06:01

有效阅读仅保存在当前浏览器,用于「为你」推荐;暂停或清除记录。

DataHot 速览

同一张 orders 表,两个工具算出的营收相差 12,350,差别只在于哪些订单算作营收。作者用 Apache Ossie 与 Snowflake semantic view 把这个口径显式写成契约,并给出 total_revenue、gross_revenue、active_customers、average_order_value 等指标的定义样例。文章指出,如果缺少表达式、过滤条件、可切片维度、依赖关系和可读描述,人、看板和 AI Agent 就会各挑一种读法,并且都说得理直气壮。

原收录理由(待核验):语义层为何是 AI 问数可信的前提,本文用具体数字和指标定义拆解了口径分歧的机制,对做 ChatBI 和指标治理的团队直接可用。

本文目录 7 节
  1. 上下文就是契约
  2. 连接也是上下文
  3. Apache Ossie 只写一次契约
  4. Snowflake 运行相同的契约
  5. 查询命名指标
  6. 智能体对此的需求,比再复制一份 SQL 更大
  7. 试用演示

译文

AI 逐段翻译

向两个工具询问同一张订单表的收入,两者都可能返回一个不同但站得住脚的数字。这就是演示中的样子。

差异是 12,350。两个查询读取相同的订单并正确执行算术。变化的是哪些订单有资格算作收入。在此演示中,只有订单完成时才计入收入。Apache Ossie 和 Snowflake 语义视图将这条规则明确化。

该定义就是上下文。它是告诉一个人、一个仪表板或一个 AI 代理,对这张表的哪种解读可以被称作收入的契约。

上下文就是契约

表存储值。上下文说明当有人提出业务问题时这些值意味着什么。对于一个指标,契约有几个部分:

  • 表达式,例如求和或计数
  • 符合条件的行,例如状态过滤器
  • 可对其切片的实体,以及这些实体如何连接
  • 它所基于的其他指标
  • 人类和模型都能阅读的描述

缺少其中任何一项,列名就会承担其余的工作。total_amount 看起来像收入。它看起来也像折扣前的收入,也像包含从未完成的订单的收入。分析师在工作表中选一种解读。仪表板选另一种。代理拿到同样的列清单,选了第三种,而且听起来很有把握。

示例模型用同一张订单表上的三个指标展示了这种区别。

total_revenue 对 order_status = 'completed' 的 total_amount 求和。在这份数据上为 103,200。

gross_revenue 使用相同的已完成订单,并将 discount_amount 加回。相同的订单,不同的问题:折扣前的价值而非折扣后的价值。

active_customers 统计在 completed、shipped 或 processing 状态下有订单的不同客户。这是比收入更宽的规则。两个指标可能不一致。在此示例中,四个未完成订单属于同时拥有已完成订单的客户,因此客户数不变。下一个只有已发货订单的客户会出现在一个指标中而不出现在另一个中。

average_order_value 不是一个新公式。它是 total_revenue / order_count。因为它建立在已完成订单指标之上,所以保留了它们的规则。对 ORDERS 中每一行手写的平均值则不会。

连接也是上下文

指标说明要聚合什么。关系说明哪条路径是安全的。

一个订单属于一个客户。一个行项目属于一个订单和一个产品。这些是多对一链接,一旦有人按区域或类别询问收入,它们就变得重要。

Region 位于客户上,而非订单上。路径是订单到客户,即多个订单对一个客户。这是对订单级收入进行分组的安全方式。Category 位于产品上,要到达它意味着经过行项目。如果你在连接行项目后对 orders.total_amount 求和,每个多行订单会按行被计数一次。关系告诉查询引擎和代理,类别切分使用行级收入,区域切分使用订单级收入。

模型有意将这些保留为单独的指标。total_revenue 是已完成订单金额。line_revenue 和 items_sold 是行项目上的求和,它们不带状态过滤器。如果类别收入也应排除未完成订单,该规则必须添加到 line_revenue 本身。只把它放在一个仪表板查询中意味着下一个使用者将看不到它。

Apache Ossie 只写一次契约

Apache Ossie(孵化中)是语义层的开放规范。它曾被称为 Open Semantic Interchange (OSI),直到该项目更名以避免与共享 OSI 缩写的其他项目混淆。该项目正在 Apache 软件基金会孵化,该基金会保持该格式开放且不受单一控制厂商的影响。

Ossie 模型是一个 YAML 文件,人和工具都能阅读。此演示中的电子商务模型命名了其来源(orders、customers、products、order_items)、它们之间的关系、用于切分结果的维度以及上述指标。该文件中的 total_revenue 携带一个求和、一个已完成订单过滤器、一个描述和标签。customer_segment 列出了它仅可取的値:Enterprise、Mid-Market 和 SMB。order_month 被定义为 DATE_TRUNC('month', order_date) 一次,因此两个仪表板不会发明两种截断方式。

项目吉祥物是一只袋鼠,将语义元数据从一个系统携带到下一个系统。从那个形象中值得保留的部分是携带。一个定义应该在从 YAML 文件到仓库、BI 工具和代理的迁移中存留下来。

Ossie 是交换格式。它不是运行查询的引擎。仍然需要有东西来执行契约。在此演示中,那个东西就是 Snowflake 语义视图。

Snowflake 运行相同的契约

一个 Snowflake 语义视图 将模型存储在表旁边。逻辑表指向物理表。关系使用主键。维度和指标成为查询可以命名的对象。注释将业务描述保留在每个对象上。

仅靠过滤器标签不足以承载指标规则。调用方可能忘记的 WHERE 子句不能保护定义。规则属于表达式内部:

orders.total_revenue AS SUM( IFF(orders.order_status = 'completed', orders.total_amount, NULL) ) COMMENT = 'Sum of total_amount for completed orders. Shipped, processing, and cancelled orders are excluded.'

average_order_value 然后引用该指标,以及 order_count,后者携带相同的谓词:

orders.average_order_value AS orders.total_revenue / NULLIF(orders.order_count, 0)

revenue_per_customer 将已完成收入除以活跃客户。每个输入保留自己的状态规则,因此该比率不会悄悄地将收入扩大到包含已发货订单。两个定义之间的分歧在模型中保持可见。

将 Ossie 文件映射到视图相当直接:

查询命名指标

一旦视图存在,一个问题就变成对一个指标和一个维度的请求。按区域划分的收入不会重述求和、状态测试或连接:

SELECT * FROM SEMANTIC_VIEW( OSSIE_DEMO.ECOMMERCE.ecommerce_semantic_model DIMENSIONS customers.region METRICS orders.total_revenue, orders.order_count ) ORDER BY total_revenue DESC;

该视图按照 total_revenue 的既定定义来应用它。另一个工作表、一个 Streamlit 应用或 Cortex Analyst 请求同一个名称时,得到的是同一份契约。演示应用中的 SQL 就是请求。含义保留在 ecommerce_semantic_model 中。

按月活跃客户这一查询同时展现了两个契约。active_customers 包含已发货和处理中的订单,而同一结果上的 total_revenue 则不然。若使用一个共享的 WHERE 子句,就会迫使两者遵循同一条规则,从而掩盖这一差异。

智能体对此的需求,比再复制一份 SQL 更大

了解业务的人可以就某个指标进行辩论并达成一致。智能体则做不到。给它表名和列名,它会写出一个看似合理的查询:对金额求和,连接它能看到的任何外键,保留所有状态。给它一个语义模型,那么合法的操作就是该模型中的指标、维度和关系。

这就是为什么一旦自然语言问题触及数据仓库,这件事就变得紧迫。智能体的一致程度取决于它所获得的上下文。Ossie 是一种编写该上下文的方式,使其不被困在单一产品中。Snowflake 语义视图则是一种让仓库强制执行该上下文的方式,其中的注释和同义词可被模型读取,表达式可被引擎实际执行。

同一份 YAML 可以转换为面向其他使用方。一次定义契约,然后让每个引擎运行它。一个只存在于单一工具内部的语义层,不过是问题的又一份副本。

试用演示

该演示是一个基于此电子商务模型、运行在 Snowflake 中的小型 Streamlit 应用。

  1. 01_setup.sql 创建 OSSIE_DEMO.ECOMMERCE 和示例表。
  2. ossie_semantic_model.yaml 是 Ossie 契约。
  3. 02_semantic_view.sql 创建 ecommerce_semantic_model,其中状态规则包含在指标内部。
  4. 应用的实时查询选项卡从该视图进行选择。

单独打开演示视频

代码: github.com/daanalytics/apache-ossie-demo

Apache Ossie 正在 Apache 软件基金会孵化。规范、邮件列表和社区位于 ossie.apache.org。Snowflake 关于该项目的文章见 Snowflake 博客。

仓库已经知道这些金额。上下文才能让其中某个金额成为收入,在每个发起询问的工具中都是如此。

最初发布于 https://www.daanalytics.nl,日期为 2026 年 11 月 3 日。

同一张表,不同的收入:Apache Ossie 与 Snowflake 来解围最初发布于 Snowflake Builders Blog:数据工程师、应用开发者、AI 与数据科学(Medium),人们正在那里通过高亮和回应此故事来继续对话。

这篇内容对你有用吗?

反馈只用于改善内容筛选,不等同于收藏

分享这条资讯
分享海报
保存图片
iOS 也可以长按图片保存