◈本体论工程手册
方法论

三 · 建模语言与约束选型

OWL / SHACL / LinkML / 属性图 / 对象类型

选型问题通常被问成「OWL 还是属性图」,但这是个伪问题。真正要选的是:你要表达的约束落在哪一层。这一章先给四层表达模型,再给语言对照表与决策树。

四层表达模型

任何语义模型要表达的东西,可以按「越往下越难执行」排成四层:

层要表达的东西典型手段可执行性
L1 结构有哪些字段、什么类型、必填还是可选JSON Schema、SQL DDL、LinkML强:几乎所有工具都能校验
L2 约束跨字段条件、枚举、基数、值域SHACL、ShEx、检查约束强:可在写入路径执行
L3 语义子类、等价、传递、逆、定义域值域OWL 2(EL/QL/RL/DL)中:需要推理机,且不报错
L4 动作前置条件、副作用、权限、回滚动作 DSL、策略引擎弱:没有标准,各家自造

这个分层解释了一个反复出现的现象:大多数「本体项目」实际只做到了 L1 和 L2,却用 L3 的语言在描述。 用 OWL 写出来的东西,如果只被当作文档和 schema 使用,那它的表达力是浪费的,而它的工具链成本是照付的。

反过来也成立:如果一个需求真的需要 L3(例如「有心脏的动物都是脊椎动物」这种可推导的分类),用 JSON Schema 是做不到的——你只能把结论手工写进数据,然后承担它随时间漂移的代价。

语言对照

语言定位表达力工具成熟度典型代价
OWL 2 EL大规模分类(SNOMED 级)存在与合取、部分角色限制高(ELK)表达力窄,写不出「至多一个」
OWL 2 RL规则可实现的子集可用前向链规则实现中(OWL-RL、Reasonable)只有 maxCardinality 0/1,表达力被规则集限制
OWL 2 QL查询重写(OBDA)可用 SQL 重写实现中(Ontop)为下推牺牲表达力
OWL 2 DL完整表达最强低且在萎缩(Pellet 停更)推理不可预测,解释困难
SHACL数据形状校验闭合世界、强校验高(pySHACL、TopBraid)不做推理,只判对错
ShEx类似的形状语言与 SHACL 接近中生态比 SHACL 小
LinkML建模语言 + 编译器L1/L2 为主,可编译到 OWL中高(41 个生成器)不是运行时,是构建期
JSON Schema接口契约L1极高表达不了图结构与跨对象约束
属性图(Cypher/GQL)存储与查询L1 + 部分 L4高无标准语义,约束靠应用层
DTDL数字孪生L1 + 遥测语义中(Azure 生态)绑生态

几条值得单独说的判断:

OWL 2 RL 的实际价值被高估了。 它常被当作「不装推理机也能推一点」的折中,但它的规则集只支持 maxCardinality 为 0 或 1 的基数限制,minCardinality 根本推不出来。如果你的需求里有「至少一个负责人」这类约束,OWL 2 RL 帮不上忙——那是 SHACL 的活。

SHACL 是这一代真正的赢家。 原因是它闭合世界、可执行、退出码明确。它不产生新知识,但它能挡住坏数据,而挡住坏数据是业务能感知的价值。第十一章会看到,这个判断有实测支撑。

LinkML 解决的是另一个问题:谁是源。 它本身不是运行时语言,而是「一份 YAML 编译到多个目标」的构建期工具。它的价值不在表达力,在于让 schema 变成可 review 的文本。

属性图不是「更差的 RDF」。 它在路径查询、存储效率、运维熟悉度上占优;它缺的是标准语义与推理。选择取决于你需要 L3 还是不需要——不需要 L3 时,属性图几乎总是更省事。

决策树

从需求出发,按顺序判断:

  1. 只需要接口契约(字段、类型、必填)? → JSON Schema。不要引入本体工具链。
  2. 需要跨字段条件、枚举、基数,并且要拒绝坏数据? → SHACL(RDF 栈)或检查约束(关系库)。判断依据是你的数据是否天然是图:多对多、层级深、关系本身带属性。
  3. 需要「从已有事实推出新事实」? → 看规模: 十万级以上类、只需分类 → OWL 2 EL + ELK 规则形态清晰、可用 Datalog 表达 → OWL 2 RL 或直接规则引擎 需要完整 DL 表达 → 先问「谁来维护解释」,多数情况下答案是「没人」,那就退回 EL
  4. 需要「表不动、语义在上层」? → OBDA(虚拟知识图)。R2RML / R2RML 方言的映射,SPARQL 重写成 SQL。
  5. 需要动作与权限? → 没有标准。自建 DSL,把动作声明成数据(参数、前置条件、副作用、权限),并把前置条件实现为第 2 步的约束。
  6. 需要一份源、多个下游格式? → LinkML 一类编译器,或自己写生成器。

一个被忽略的选型维度:谁改它

表达力之外,还有一个维度决定成败:变更的日常执行者是谁。

  • 如果改模型的人是数据工程师,用 YAML + git,他会很舒服;给他 Protégé,他会绕着走。
  • 如果改模型的人是领域专家,用表格或可视化编辑器;给他 Turtle,他会在两周内放弃。
  • 如果两边都要改,就必须有一个「生成物」和一个「源」,且明确哪边不许手改。

这一点比表达力更能预测项目存活率。推断:选型时把「变更执行者」放在第一位,把表达力放在第二位,能显著降低「建完就没人维护」的概率。

反模式:用上层语言写下层需求

最常见的浪费是把 L2 的需求用 L3 的语言写:

  • 需求其实是「这个字段必填、这个枚举有五个值」
  • 实现却用 OWL 的基数限制与枚举类
  • 结果:需要推理机才能校验,推理机不报错,校验实际没生效

正确的做法是同一个模型里分层:结构用 L1、约束用 L2 并真的执行、只在确实需要推导的地方用 L3,且明确标注「这一段有推理依赖」。这样即使推理机被下线,前两层仍然有效。