Lesson 04 · 约束建模
用约束建模
声明"看不见的规则",让推理器替你推导与校验
前面你学会了声明类、属性、子类、domain/range。这一课再上一步:声明规则(公理, axiom)。规则不是在代码里写的 if/else,而是声明式地说给推理器听,由它统一执行。于是推理器能做两件关系数据库不擅长的事:推导与校验。
01先把"公理"说成人话
公理 = 你声明的、不必手写的规则。像关系数据库里的 CHECK / NOT NULL 约束——但更进一步:它除了拦下不合规的数据,还能推导出没明说的事实。
你去银行办事。柜员不是每个客户都现场再教一遍规则,而是把规则写死在系统里(如"余额不能为负""身份证必须有效")。规则声明一次,之后系统自动校验、并按这些规则处理。本体的公理就是"写死的规则",交给推理器执行。
问题是:这些规则怎么写?本体用几种标准公理,下面三样最常用。
02三种常用公理
| 公理 | 说人话 | 推理器用它做什么 | 供应链计划例 |
|---|---|---|---|
等价类 owl:equivalentClass | "这两个词说的是同一种东西" | 把两边的个体合并/互换 | 「在售」≡「可下单」(两系统同一概念) |
不相交 owl:disjointWith | "这两个类没有共同个体" | 发现矛盾:某个体同时属两者即报错 | 「成品」⊥「原材料」 |
基数 min/max/exactlyCardinality | "某类对某属性至少/至多/恰好 N 个" | 推导+校验数量关系 | 每张订单至少 1 个物料;每个 SKU 至多 1 个当前提前期 |
基数约束在 Web 本体语言(OWL)里写成"限制"owl:Restriction;上面意思是:Order 的子类 —— 每个订单对 requiresProduct 至少有 1 个取值。
03推理器的两件事:推导 与 校验
把公理和事实一起喂给推理器,它做两件不同的事:
| 动作 | 什么意思 | 例子 |
|---|---|---|
| 推导 | 从已有知识推出未明说的新知识 | 成品⊑产品 + sku 是成品 ⇒ sku 是产品 |
| 校验 | 发现矛盾,告诉你"不一致" | 某个体既声明为成品、又声明为原材料 ⇒ 报矛盾 |
关系库的 CHECK 只在写入时拦一次(闭世界);本体公理在开放世界下由推理器统一执行——既推导新事实,又校验矛盾,而且是声明式的:想改规则就改声明,不用动代码。[1]
04落回你的产能
还记得 0003 说"产能若带属性,就再化成类"吗?把它接上公理,威力就出来了:
- 产能是约束 → 建模成
CapacityAllocation(资源 × 时段 × 数量)。 - 加一个基数公理:"一个资源、一个时段,至多一个产能分配"。
- 于是推理器能校验:若有人给 7 号线、6 月排了两份产能,它就报"冲突/超排"——不用你写一堆判断。
05检查你的理解
要声明「成品」和「原材料」没有共同的个体,用哪个公理?
「每张订单至少需要 1 个物料」是什么约束?
用公理后,推理器能做哪两件事?
想更工程化地理解"声明式规则 vs 手写判断",见 Semantic Web for the Working Ontologist 的约束相关章节。
[1] 万维网联盟(World Wide Web Consortium, W3C),Web 本体语言(OWL)入门 —— 等价类 / 不相交 / 基数限制 / 推理语义。
这一课记住一句:公理是声明式规则,让推理器替你推导和校验,而不是你写代码判断。想把你真实业务的某条约束(比如"一个物料只能有一个主供应商")写成公理,直接问我,我帮你建模。