在学习中,在劳动中,在科学中,在为人民的忘我服务中,你可以找到自己的幸福。——捷连斯基

https://github.com/apache/ossie

Apache Ossie:给语义模型交换搭一条真正能走通的路

数据世界里最常见的麻烦,往往不是没有定义,而是定义太多。一个 KPI 在这个工具里这样写,到了另一个平台里又换了名字、换了结构、换了表达方式。表面上看,大家都在做“语义建模”,可一旦跨平台、跨团队、跨工具协作,语义就像被拆成了很多互不相认的方言。

Apache Ossie 想做的,正是把这件事重新讲清楚。

它是一个协作式的开源项目,专注于标准化并简化语义模型在不同工具和平台之间的交换与使用。更进一步地说,它试图在分析、AI 和 BI 平台之间,为语义元数据建立一种行业范围内的统一交换方式,提供一个厂商中立的单一事实来源。这不是一句轻飘飘的愿景,而是整个项目最鲜明的主线。

项目地址:https://github.com/apache/ossie

从 Open Semantic Interchange 到 Apache Ossie

Apache Ossie 以前的名字是 Open Semantic Interchange,简称 OSI。名字变了,但它关心的问题没有变:如何让语义模型不再被困在各自的平台边界里,如何让一份模型被不同工具读懂、写入、转换、复用。

README 里有一句很关键的话:Apache Ossie 提供了一个基于 JSON 和 YAML 的统一规范,任何工具都可以读取和写入。它要解决的,是今天数据技术栈中非常典型的语义碎片化问题——同样一个 KPI,在不同工具里可能会被定义出不同版本,最终让“同一个业务概念”在不同地方长成不同模样。

换句话说,Apache Ossie 不是单纯在发明一种新格式,它更像是在试图搭起一座桥,让原本互相隔着河流的平台,终于有了彼此往来的道路。

它的核心目标很直接:让语义模型交换变得有共同语言

很多项目谈“标准化”时,容易陷入抽象,但 Apache Ossie 在仓库首页给出的表达非常落地。它所提供的是单一规范,而且明确采用 JSON 和 YAML 作为承载形式。这种选择非常实用:既强调机器可读,也保留了足够清晰的人类可读性。

更重要的是,这个规范不是为了某一个特定产品服务,而是为了在多种工具与平台之间建立共同理解。这里的关键词是“vendor neutral”。它不把某个厂商格式当作中心,而是试图让语义元数据拥有一个中立的、可交换的表达层。

这种定位让 Apache Ossie 看起来不像是某个封闭生态里的零件,反而更像是一个试图打通边界的公共接口。

仓库里有什么:它把蓝图、桥梁、样例和校验工具都摆在了一起

Apache Ossie 的 README 很清晰地列出了仓库的主要组成部分。整个仓库结构像是一套完整的施工现场图纸,每一块都各司其职。

core-spec/

这里放的是 Ossie 的核心规范,包括:

  • spec.md
  • 机器可读的 schema
  • spec.yaml
  • osi-schema.json
  • 配套文档

这部分像项目的骨架。规范写在这里,结构定义也写在这里。它不只是“有一个想法”,而是把这个想法落实成可被程序理解、可被工具验证的正式表达。

converters/

这里是参考转换器所在的位置,用来在 Ossie 与其他语义格式之间进行翻译。README 中明确举出的例子包括:

  • dbt
  • GoodData
  • Polaris
  • Salesforce

这一部分非常关键,因为标准只有在能与现实世界对话时才真正有生命力。转换器的存在,意味着 Ossie 不只是一个静态规范,而是试图进入实际工具链,参与真正的格式转换工作。

examples/

这里提供了示例语义模型,其中包括一个完整的 TPC-DS model。示例的意义很朴素,但非常重要:它让规范不只停留在纸面上,而开始长出具体形状。

validation/

这里放的是根据 Ossie schema 验证语义模型的工具。一个规范如果没有验证机制,就很容易停在“大家都可以理解”的幻想里;而有了验证工具,规范就真正开始具备执行力。

docs/

这里是项目文档和整体说明所在的位置。它让这个仓库不仅仅能被机器消费,也能被人系统地理解。

一个很有代表性的设计:Hub-and-Spoke 架构

converters/README.md 里,Apache Ossie 给出了自己在转换层上的核心思路:hub-and-spoke

这个结构非常形象。

  • Hub:Ossie 核心规范,作为中心的、厂商中立的格式
  • Spokes:每个转换器负责与某一个厂商格式之间的双向翻译

文档里甚至画出了一个非常直观的结构图:Ossie 在中心,Snowflake、dbt、Salesforce、Databricks 等围绕四周,与它相连。

这个思路的妙处在于,它避免了每个厂商之间都各自去做点对点转换。如果采用点对点方式,随着厂商数量增长,转换器数量会迅速膨胀;而以 Ossie 为中心时,每个厂商只需要和这个中立规范对接。

这不只是架构上的优雅,更是一种非常现实的复杂度控制方式。Apache Ossie 在这里扮演的,不是某个终点格式,而是一个中转站,一个语义世界里的交通枢纽。

转换器在这里不是配角,而是整个生态的行动派

Ossie Converter 的职责被写得很明确:它负责 Ossie 与特定厂商语义实现之间的双向翻译。

Export:从 Apache Ossie 到 Vendor

这条路径做的是,把 Ossie 语义模型读进来,再输出对应厂商自己的语义表示。文档中举的例子包括:

  • Ossie → Snowflake semantic model definition
  • Ossie → dbt semantic_models YAML
  • Ossie → Tableau data source / Salesforce semantic layer
  • Ossie → Databricks semantic layer definition

Import:从 Vendor 到 Apache Ossie

反方向则是读取厂商格式,再生成一个有效的 Ossie 模型,并把厂商特有的元数据映射进 custom_extensions

这套设计很耐看。它不是强迫所有平台“忘掉自己”,而是允许每个厂商保留自身的特性,同时通过 custom_extensions 把那些无法直接进入核心规范的细节带上。这样一来,标准化并不等于削平差异,而更像是在差异之上搭建共同语法。

它已经明确列出了一批支持扩展的厂商方向

converters/README.md 中,Ossie 当前定义了以下厂商扩展:

Vendor Description
SNOWFLAKE Snowflake semantic model
SALESFORCE Salesforce / Tableau semantic layer
DBT dbt semantic models
DATABRICKS Databricks semantic layer
OMNI Omni semantic model

这张表很短,但意义不小。它说明 Ossie 的核心规范并不是抽象地悬在空中,而是已经明确考虑到如何承接不同平台的语义实现方式。与此同时,它也说明 custom_extensions 是项目中非常重要的一层:当核心规范与厂商能力不完全重合时,扩展字段就是那只负责“把信息完整带回来”的手。

它对语义模型的拆解非常细,几乎是在一层层教人如何翻译

converters/README.md 最有价值的部分之一,是它不是只讲原则,而是把语义模型中的关键构件一项项拆开来讲:Semantic Model、Datasets、Fields、Relationships、Metrics、Custom Extensions、AI Context

这让整个项目一下子变得具体起来。

Semantic Model:顶层容器

语义模型作为顶层对象,包含:

  • name
  • description
  • ai_context
  • datasets
  • relationships
  • metrics
  • custom_extensions

这一层像整本书的封面与目录,把后续所有内容组织起来。

Datasets:逻辑数据集

Datasets 代表逻辑表,可以是事实表,也可以是维度表。文档中列出的字段包括:

  • name
  • source
  • primary_key
  • unique_keys
  • fields
  • ai_context
  • custom_extensions

这里能看出 Ossie 并不只想表达“有哪些表”,它也在意这些表如何被引用、如何定义主键、如何承载业务语义。

Fields:字段不仅是列名,也可以是表达式

Fields 代表行级属性。它们既可以是简单列引用,也可以是计算表达式。相关字段包括:

  • name
  • expression.dialects
  • dimension.is_time
  • label
  • description
  • ai_context

特别值得注意的是 expression.dialects。Ossie 明确考虑到了多方言 SQL 表达式的场景。文档给出的例子中,同一个字段可以同时提供 ANSI_SQLSNOWFLAKE 的表达式版本。

1
2
3
4
5
6
expression:
dialects:
- dialect: ANSI_SQL
expression: LOWER(email)
- dialect: SNOWFLAKE
expression: LOWER(email)::VARCHAR

这背后体现出的不是简单的兼容,而是一种很务实的转换哲学:不同平台可以有自己的表达习惯,但同一个语义定义仍然应该能被系统地映射。

Relationships:关系不仅能表达连接,还能处理复合键

Relationships 用来定义数据集之间的外键关系。文档中提到的关键字段包括:

  • name
  • from
  • to
  • from_columns
  • to_columns

它还特别强调支持简单键和复合键。例如这样的定义:

1
2
from_columns: [product_id, variant_id]
to_columns: [id, variant_id]

它表示的是一个多列 join 条件。也就是说,Ossie 并没有把关系简化成过于理想化的单列连接,而是把现实建模里常见的复杂情况也纳入了规范表达。

Metrics:指标被放在语义模型级别来定义

Metrics 是聚合度量,定义在语义模型层面,并且可以跨多个数据集工作。相关字段包括:

  • name
  • expression.dialects
  • description
  • ai_context

文档给出的跨数据集指标示例是这样的:

1
2
3
4
5
- name: customer_lifetime_value
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(store_sales.ss_ext_sales_price) / COUNT(DISTINCT customer.c_customer_sk)

这段例子很有代表性。它说明指标定义并不局限于某张单表,而是允许通过关系把多个数据集串联起来。也正因为如此,转换器在实现时不仅要看表达式本身,还要确保相关数据集引用和 join 关系能被正确还原到目标平台。

custom_extensions:标准化之外,仍然给差异留下合法位置

一个真正成熟的交换规范,往往不是把差异完全抹平,而是给差异安排一个可控的容器。Apache Ossie 里的这个容器,就是 custom_extensions

文档中说明,厂商特有的元数据会以 JSON 字符串的形式放在 custom_extensions 中。转换器在导出时,需要提取与目标厂商匹配的扩展项;在导入时,则要把那些没有 Ossie 核心等价物的配置保存回来。

Snowflake 的例子写得非常直观:

1
2
3
custom_extensions:
- vendor_name: SNOWFLAKE
data: '{"warehouse": "ANALYTICS_WH", "database": "PROD", "schema": "PUBLIC"}'

这说明 Ossie 的态度不是“核心规范之外的内容都不重要”,而是“核心规范先承载共性,个性则放进扩展层中保存”。这种做法既保证了中立性,也照顾到了现实差异。

ai_context 的出现,让它不仅关心数据结构,也关心语义表达

在文档中,ai_context 出现在模型、数据集、字段、关系和指标等多个层级。它既可以是简单字符串,也可以是结构化对象。

简单形式:

1
ai_context: "orders, purchases, sales"

结构化形式:

1
2
3
4
5
6
7
ai_context:
instructions: "Use this for sales analysis"
synonyms:
- "orders"
- "purchases"
examples:
- "Show total sales last month"

这一部分非常耐人寻味。它表明 Ossie 不只想处理“字段长什么样、关系怎么连、指标怎么算”,还想保存那些帮助 AI 或工具理解业务语义的上下文信息。也就是说,它关注的不只是模型的结构层,还包括模型被解释、被查询、被消费时所需要的语义辅助层。

文档把“如何写一个转换器”写成了一份可执行清单

converters/README.md 里还有一段非常实在的内容:Writing a Converter。它几乎是一步一步把实现路径铺出来。

它给出的步骤包括:

  1. 验证输入
    使用 Ossie JSON Schema 和验证脚本,确保源模型有效。

  2. 解析 Ossie 模型
    读取 YAML,遍历顶层 semantic_model 条目。

  3. 映射 datasets
    namesourceprimary_keyunique_keysfields 等转为厂商格式。

  4. 处理字段方言选择
    优先使用厂商特定 dialect,缺失时回退到 ANSI_SQL,如果都没有则给出警告或错误。

  5. 映射 relationships
    把关系定义翻译成目标平台的 join 语法,并保持复合键列顺序。

  6. 映射 metrics
    使用与字段相同的方言选择逻辑,并正确解析数据集引用。

  7. 应用 custom_extensions
    提取匹配目标厂商的扩展项并应用。

  8. 保留 ai_context
    如果目标平台支持,就映射;如果不支持,则尽量保留。

  9. 验证输出
    确保生成的厂商模型对该厂商自己的工具链而言也是有效的。

这份步骤清单的价值在于,它不是只谈概念兼容,而是直接进入实现细节。读到这里,很容易感受到 Apache Ossie 想做的不是一个“愿景型”标准,而是一个真正打算被工程化落地的标准。

它对边界情况也不回避

文档里还专门列出了若干边界情况的处理建议,比如:

  • 字段或指标缺少厂商专用 dialect 时,回退到 ANSI_SQL
  • 计算字段使用厂商专有 SQL 时,需要源模型中提供对应方言
  • 复合主键需要确认目标平台是否支持
  • 跨数据集指标需要确保所有引用的数据集存在且关系已定义
  • 未知厂商的扩展应忽略但保留
  • 如果目标厂商不支持 ai_context,则用 vendor_name: COMMONcustom_extension 形式保留

这种写法很有分寸。它不假装一切都能完美无损地互转,但它尽可能把每一种信息都安顿好,避免在转换过程中悄悄丢失。

Round-Trip Fidelity:它追求的不只是“能转”,还包括“尽量不丢”

在语义交换这件事上,真正难的从来不是第一次导出,而是来回走一遍之后,信息还能不能尽量保住。

Apache Ossie 在文档里明确提出了 Round-Trip Fidelity 的目标,也就是:

1
Vendor A model → [Import] → Ossie model → [Export] → Vendor A model

为了尽可能保持这条链路的完整,它提出了几个原则:

  • 不要默默丢弃信息
  • 尽量保留字段顺序
  • 保留所有厂商的 custom_extensions,而不是只保留当前目标厂商的部分

这是一种非常成熟的思路。因为一旦一个交换格式只能“出去”,却不能尽量完整地“回来”,它就很难真正成为生态中的中立枢纽。Apache Ossie 在这里显然是想把这件事做得更扎实一些。

TPC-DS 示例,让整套思路落到了具体模型上

examples/ 目录中,仓库给出了完整的 TPC-DS 示例模型。converters/README.md 还用它举了一个 Snowflake 导出转换的概念流程,包括:

  1. 读取 tpcds_retail_model
  2. 创建同名的 Snowflake semantic model
  3. store_salesdate_dimcustomeritemstore 等数据集映射成 Snowflake 表引用
  4. 为字段选择 ANSI_SQL dialect
  5. 把 relationships 翻译成 Snowflake join 定义
  6. total_sales 这类 metrics 转成 Snowflake 指标定义
  7. 提取 SALESFORCEDBTcustom_extensions,虽然不会应用到 Snowflake 输出,但会为后续往返保留信息

这段流程特别能体现 Ossie 的风格:它不是抽象地喊“我们支持转换”,而是把转换路径一段段拆开,让人真正看到这座桥是怎么搭起来的。

它也把新厂商接入的路径说明白了

如果要为新的厂商增加支持,文档给出的步骤包括:

  1. 为转换器输出的每个 custom_extension 使用稳定的 vendor_name
  2. 定义该厂商的自定义扩展 schema
  3. 实现导出转换器
  4. 实现导入转换器
  5. 使用 TPC-DS 示例模型添加测试
  6. 记录限制和暂不支持的内容

这种写法很像一份门口贴着的施工流程单:想加入,可以;规则写明白了,路径也留好了。对于一个希望成为跨平台交换标准的项目来说,这种开放而有秩序的接入方式非常重要。

这个仓库本身,也在努力构建一个开放协作的项目现场

README 里的 “Get involved” 部分也很清楚,它把参与路径拆成了几条:

  • 贡献:查看 CONTRIBUTING.md
  • 路线图:查看 ROADMAP.md
  • 讨论:通过 GitHub Discussions 和 Issues 参与
  • 社区沟通:加入 Slack

这些内容看起来简单,却让整个项目多了一层温度。标准化从来不是一个人坐在房间里定义出来的,它更像是一场需要不断对齐、不断讨论、不断修订的集体工程。Apache Ossie 把这些参与入口明明白白摆出来,本身也说明它把“共同制定标准”这件事看得很重。

为什么 Apache Ossie 值得被认真看待

Apache Ossie 最打动人的地方,不在于它把术语写得多复杂,而在于它非常明确地盯住了一个现实问题:语义元数据在分析、AI 和 BI 平台之间是碎裂的,而这种碎裂会持续制造重复定义、重复翻译和重复理解的成本。

它给出的回应也很清楚:

  • 用统一的 JSON / YAML 规范承载语义模型
  • 用厂商中立的核心规范做中心
  • 用 hub-and-spoke 的转换架构连接不同平台
  • custom_extensions 保存平台差异
  • ai_context 承载更丰富的语义说明
  • 用 schema、样例和验证工具把规范变成可执行资产

如果把整个仓库读下来,会发现 Apache Ossie 并不是那种只停留在概念层的项目。它已经把规范、转换、验证、示例和接入路径逐步铺开,让“语义模型交换”这件事开始具备一种可以被实践、被扩展、被讨论、被落地的形状。

它像是在一片语义碎片四散的地形上,认真地铺设一条轨道。轨道并不会替所有平台做决定,但它让彼此之间终于有了一种可预期的通行方式。而这,恰恰是标准最有价值的时候。