2. 知识图谱基础:三元组、RDF、属性图、图数据库
知识图谱这东西,说到底就是把世界上的事物用“关系”串起来。你想想看,药物可以治疗疾病,药物有副作用,基因与疾病相关……这些关系放到一起,就是一个巨大的网络。我开始做药物重定位的时候,第一次接触知识图谱,当时就只有一个感受:这玩意儿太适合解决跨领域关联问题了。
但光有感受不行,得理解底层到底是怎么存的、怎么查的。这一节我就把四个核心概念串起来讲:三元组、RDF、属性图、图数据库。它们环环相扣,搞懂了,后面做特征分析才有底气。
2.1 三元组:知识图谱的最小单元
知识图谱里最基础的存储单元就是三元组。格式极其简单:
(主体, 关系, 客体)
说白了就是“主语-谓语-宾语”那一套。举个例子:
(二甲双胍, 治疗, 2型糖尿病)
这就代表“二甲双胍”这个药,有关系“治疗”,指向“2型糖尿病”。
我在项目里整理数据时,经常会碰到主体和客体都是药物的情况,比如:
(阿司匹林, 相互作用, 华法林)
这种二元关系用三元组存起来,机器就能直接理解。你想想看,如果我们把几万、几百万条这样的三元组拼到一起,是不是就是一个知识网络?
核心要点:三元组是图的边(关系),而主体和客体就是图的节点。每一个三元组就是一条有向边。
2.2 RDF:让三元组有了标准
有了三元组还不够,不同系统之间怎么交换数据?这时候RDF(Resource Description Framework)就站出来了。它是W3C定的一套标准,给每个实体一个全局唯一的URI,这样大家引用的资源就不会混淆。
举个例子,用Turtle格式写一个RDF三元组:
<http://example.org/drug/metformin>
<http://example.org/predicate/treats>
<http://example.org/disease/type2diabetes> .
看着挺啰嗦的,对吧?但好处是全局唯一,我当年对接外部数据源时,就靠URI避免了无数“同名不同义”的坑。
RDF还有几种常见的序列化格式:
| 格式 | 特点 | 常见场景 |
|---|---|---|
| Turtle(.ttl) | 简洁, 可读性好 | 手动编辑、小规模数据 |
| RDF/XML | 标准交换格式 | 企业系统、语义网工具 |
| JSON-LD | 与JSON兼容 | Web API、前端集成 |
| N-Triples | 每行一个三元组,最朴素 | 大数据批量导入 |
我的经验:在药物重定位项目里,我优先用Turtle写原型,因为可以手工调。等数据量到百万级,改成N-Triples用RDF4J批量导入,性能差很多。
2.3 属性图:更贴近开发者的视角
RDF虽然标准,但有些场景用着别扭。比如要给一个药物节点加上“分子量”、“半衰期”这些属性,RDF里得拆成多个三元组,维护起来有点繁琐。这时候属性图模型就出现了。
属性图的核心思想很简单:节点和关系都可以带属性(键值对)。比如一个药物节点:
Node: Drug_Metformin
Properties:
name: "二甲双胍"
molecular_weight: 129.16
half_life: 6.2 // 单位小时
关系也可以带属性,比如“治疗”关系可以写上“证据等级:A级”。这一点我在做知识图谱特征工程时特别有用——可以直接把属性作为特征喂给模型。
比较一下RDF和属性图:
| 维度 | RDF | 属性图 |
|---|---|---|
| 节点标识 | IRI(全局URI) | 本地ID(可全局) |
| 关系表达 | 三元组边 | 命名关系(可带属性) |
| 属性存储 | 拆成多个三元组 | 键值对直接挂在节点/边上 |
| 查询语言 | SPARQL | Cypher、Gremlin |
| 主要用途 | 语义网、数据交换 | 图数据库、知识图谱应用 |
避坑:我曾经在同一个项目里同时用RDF和属性图存储同一份数据,结果发现对齐实体成本极高。新项目我建议只选一种模型。如果数据需要频繁与外部交换,选RDF;如果主要是内部查询和推理,属性图更顺手。
2.4 图数据库:把图存下来、查出来
有了图模型,总得有个地方存吧?图数据库就是专门干这个的。它针对图的遍历(比如从某个药物出发,沿“治疗”关系找到所有疾病)做了深度优化,比你用关系数据库的JOIN快得多。
常见的图数据库:
- Neo4j:属性图数据库的标杆,查询语言Cypher。社区活跃,文档齐全。我自己最开始就是从Neo4j入门的。
- JanusGraph:支持大规模分布式图,底层用Cassandra或HBase。适合超大数据量。
- Virtuoso / RDF4J:专为RDF设计,支持SPARQL。适合语义网场景。
举个例子,用Cypher查询“二甲双胍治疗的所有疾病”:
MATCH (drug:Drug {name: '二甲双胍'})-[r:TREATS]->(disease:Disease)
RETURN disease.name, r.evidence_level
用SPARQL查同样的东西:
PREFIX drug: <http://example.org/drug/>
SELECT ?disease ?level WHERE {
drug:metformin drug:treats ?disease .
OPTIONAL { ?disease drug:evidenceLevel ?level . }
}
个人建议:做药物重定位项目,前期数据量不超过千万级,Neo4j + Cypher是最快上手的选择。等需要跨机构数据交换时,再考虑RDF + SPARQL。
2.5 知识图谱基础框架图
下面这张SVG图把从三元组到图数据库的整体关系画出来了。你一看就明白它们之间怎么衔接的。
2.6 小结
这几个概念一开始可能觉得有些抽象,但实际用起来没想象中复杂。说白了,三元组就是积木块,RDF和属性图是两种搭建方式,图数据库就是搭好之后的乐高底板。我做药物重定位的第一步,就是把公开数据库(DrugBank、DisGeNET)转换成这些图结构,然后才能做特征分析。
记住一句话:选对模型,事半功倍。数据需要广泛交换?用RDF。需要快速查询和属性扩展?用属性图。
我的建议:刚开始学的时候,先动手建一个小型知识图谱(比如100个三元组),用Neo4j Desktop跑一遍Cypher。亲手操作比看十遍书都管用。