知识表示基础:RDF、RDFS、OWL、属性图模型与三元组
说到知识图谱,最绕不开的就是「怎么把知识装进去」。我刚开始接触这个领域时,也被一堆缩写搞得晕头转向——RDF、RDFS、OWL…… 后来花了很长时间才理清它们之间的关系。说白了,这些就是一套「给世界万物编字典」的规则。
实体 - 关系 - 属性三元组:最小知识单元
先看最基础的。知识图谱里,最小的知识单元就是一个三元组:
- 实体(Subject)—— 你要描述的那个东西
- 关系(Predicate)—— 连接两个实体的那条线
- 实体/属性值(Object)—— 关系的另一端,可以是另一个实体,也可以是具体的值
举个我项目里的例子:描述“张三是某公司的员工”。三元组就是:
张三 -- 就职于 -- 某公司
这里“张三”和“某公司”是实体,“就职于”是关系。如果我想表达“张三的年龄是35岁”,三元组变成:
张三 -- 年龄 -- "35"
注意,这里的“35”是个字面量(属性值),不是实体。这就是实体 - 关系 - 属性三元组的基本套路。
RDF:资源描述框架
RDF(Resource Description Framework)是 W3C 搞出来的标准,用来表达三元组。它规定了三元组的序列化格式,比如 Turtle、XML、N-Triples 等。你看这个 Turtle 例子:
@prefix ex: <http://example.org/> .
ex:张三 ex:就职于 ex:某公司 .
ex:张三 ex:年龄 "35"^^xsd:integer .
每个三元组用句点结束,前缀用于缩短 URI。RDF 的核心思想是「万物皆资源,用 URI 命名」。我刚开始写 RDF 时老忘记加前缀,结果 URI 写满了整行,像个怪物。
但 RDF 有个局限——它不限制你用什么关系,也不定义实体类型。比如你可以写:
ex:张三 ex:是 ex:人类 .
ex:张三 ex:是 ex:超能力者 .
系统并不知道“人类”和“超能力者”是什么,也不会阻止你犯逻辑错误。这时候就需要 RDFS 或 OWL 来加约束了。
RDFS:加一层「类的谱系」
RDFS(RDF Schema)就像是给 RDF 加了一个「概念说明书」。它允许你定义类(Class)和属性(Property)的层级关系。比如:
ex:人类 rdf:type rdfs:Class .
ex:程序员 rdfs:subClassOf ex:人类 .
ex:年龄 rdf:type rdf:Property .
ex:年龄 rdfs:domain ex:人类 .
ex:年龄 rdfs:range xsd:integer .
这样系统就知道:程序员是人类的子类,年龄这个属性的定义域是人类,值域是整数。我遇到过一个坑:团队里有人把年龄的关系用在公司节点上,结果推理器报了错,就是因为没加 domain 约束。RDFS 能帮你做基础的推理,比如:如果“张三 is a 程序员”,而“程序员 is a 人类”,那么系统可以推断出“张三 is a 人类”。
OWL:更强大的推理武器
OWL(Web Ontology Language)在 RDFS 基础上又升级了。它能表达更复杂的逻辑关系,比如:
- 等价关系:
ex:父亲 owl:equivalentClass ex:爸爸 - 互斥关系:
ex:男人 owl:disjointWith ex:女人 - 属性特征:
ex:配偶 rdf:type owl:TransitiveProperty(表示传递性) - 数量约束:
ex:人类 owl:minCardinality "1"^^xsd:integer ; owl:onProperty ex:母亲
举个例子,你可以在 OWL 中定义:
ex:人类 owl:disjointWith ex:非生物 .
ex:人类 rdfs:subClassOf [
rdf:type owl:Restriction ;
owl:onProperty ex:母亲 ;
owl:minCardinality 1
] .
这样推理器就能检查出:如果某个实体同时被标记为“人类”和“非生物”,那就出错了。我在做一个医疗知识图谱时,用 OWL 定义了药物的禁忌症互斥关系,确实省去了很多手工校验的工作。
但 OWL 也有代价——计算复杂度高,大规模数据里跑推理可能很慢。一般我会根据场景选 OWL 的子语言,比如 OWL 2 RL 或 EL,它们能在可接受的时间内完成推理。
属性图模型(Neo4j):更自由的图数据库
说完 RDF 家族,再来看另一种主流模型——属性图模型。Neo4j 就是典型代表。它不搞三元组那一套,而是用节点 + 关系 + 属性来建模:
- 节点:可以带标签(Label),比如
Person、Company - 关系:有方向、有类型,比如
[就职于],还可以带属性 - 属性:K-V 对,挂在节点或关系上
在 Neo4j 里,上面的例子用 Cypher 写就是:
CREATE (:Person {name: '张三', age: 35})
-[:就职于 {入职年份: 2019}]->(:Company {name: '某公司'})
你会发现,属性图模型把属性直接内嵌到节点和关系里,不用再单独建立字面量节点。这在某些场景下查询更快。我做过一个实时推荐系统,用属性图模型比用纯 RDF 存储效率高很多,因为属性图可以快速沿着关系遍历。
但属性图模型也有弱点——它不支持 RDFS/OWL 级别的推理。如果你想自动推断出“张三 is 人类”,需要在应用里自己实现推理逻辑。所以我的经验是:
核心对比:一张表说清楚
为了方便对比,我把这几种表示方式整理成表格:
| 模型 | 核心单元 | 推理能力 | 典型工具 | 适合场景 |
|---|---|---|---|---|
| 三元组(基础) | (实体, 关系, 实体/属性值) | 无 | 任意 | 数据采集、初步存储 |
| RDF | 三元组 + URI | 无 | Jena, RDF4J | 统一表示、数据交换 |
| RDFS | 类 + 属性层级 | 类层次推理 | Jena, Protege | 概念建模、简单约束 |
| OWL | 公理 + 约束 | 强推理 | Pellet, HermiT | 复杂领域、一致性校验 |
| 属性图模型 | 节点 + 关系 + 属性 | 无(需自定义) | Neo4j, JanusGraph | 图遍历、性能敏感场景 |
完整知识体系结构图
下面这张 SVG 图展示了本章的知识体系:从基础三元组出发,分别走向 RDF 体系(RDF→RDFS→OWL)和属性图体系,以及它们在关联校验中的角色。
小结与实战准备
好了,这一章我把知识表示的核心概念过了一遍。你可能会问:这些跟我做关联校验有什么关系?嗯,关系很大。前面提到的 RDFS 和 OWL 推理能力,正是我们后面做规则校验、冲突检测时的底层引擎。而属性图模型则是我们做路径分析和模式匹配时的利剑。