知识图谱基础:实体、关系、三元组及其在图数据库中的表示
各位好,咱们今天聊点实在的。
你想想看,药物研发中最头疼的是什么?不是数据不够,而是数据太散。靶点、化合物、基因、疾病、临床实验……这些信息分散在PubMed、ChEMBL、DrugBank、ClinicalTrials.gov里,彼此之间是什么关系?没人给你画好。我早期做靶点发现时,光打通这些数据就花了大半年。后来接触知识图谱,才觉得——嗯,这才是搞生物信息学该用的工具。
知识图谱说白了,就是把世界上的事物和它们之间的关系,用一张图组织起来。今天咱们就拆开揉碎了,讲讲它的核心:实体、关系、三元组,以及它们在图数据库里是怎么存的。
1. 三元组:知识的最小单元
别被“三元组”这个名字唬住。它就是三个东西:主体、关系、客体。
格式很简单:(主体, 关系, 客体)。
举个例子:
EGFR是致癌基因?这么表达:
(EGFR, is_a, 致癌基因)
这种表达方式在知识图谱里叫“事实陈述”。每个事实就是一条边,连接两个节点。我习惯用RDF(Resource Description Framework)来表示,它在语义网里是标准。
三元组有几个好处:
- 标准化:每条都是一个独立事实,便于合并和查询。
- 可推理:有了A→B和B→C,就能推出A→C。
- 可链接:不同来源的数据可以用同一实体或关系对齐。
2. 实体与关系的定义
在药物KG里,实体和关系都带了很强的领域色彩。
| 概念 | 在药物KG中的例子 |
|---|---|
| 实体 | 基因、蛋白质、化合物、疾病、症状、临床实验、文献 |
| 关系 | 靶向、抑制、激活、突变、治疗、副作用、参与通路 |
我早年在做一个靶点-药物关联项目时,就掉进过一个坑。当时的实体定义太粗——把所有“蛋白”都当同一类,结果EGFR和HER2虽然是同家族,但功能完全不同,推理结果一塌糊涂。后来我把实体细分为“激酶受体”、“信号转导蛋白”、“转录因子”等子类,准确率大幅提升。
3. 从三元组到图数据库
三元组怎么存?你可以用关系型数据库——但那我就不推荐了。因为每次查询都要做JOIN,层数一多就炸。图数据库才是正道。
我举个例子,用Neo4j的Cypher查询语言。假设我们要查:哪些药物靶向EGFR?
MATCH (drug:Drug)-[:TARGETS]->(gene:Gene {name: 'EGFR'})
RETURN drug.name
这个查询在关系型数据库里可能需要三次JOIN,但图数据库一次遍历就搞定。为什么?因为图数据库是按“边”来存储和索引的。
底层存储结构其实不复杂:每张表存一个关系类型,每行存主体和客体的ID。比如:
| 主体ID | 关系 | 客体ID |
|---|---|---|
| Drug:001 | TARGETS | Gene:011 |
| Drug:002 | TARGETS | Gene:011 |
| Gene:011 | PARTICIPATES_IN | Pathway:005 |
这样存,上层查询几乎不用考虑“表结构”的问题。你只需要沿着关系走就行。
4. 图数据库的两种主流模型
目前图数据库主要分两类:RDF图和属性图。我接触过两者,说说区别。
| 特性 | RDF图 | 属性图 |
|---|---|---|
| 节点定义 | URL标识,可跨库链接 | 本地ID,属性和标签丰富 |
| 关系定义 | RDF属性(也是URL) | 有方向、类型、属性 |
| 查询语言 | SPARQL | Cypher / Gremlin |
| 推理能力 | 强(基于OWL/RDFS) | 弱(需要应用层实现) |
| 适用场景 | 开放数据(生物医学KG常选) | 企业级应用、实时分析 |
我做药物KG初期,图方便用了属性图。结果后来需要跨知识库链接——比如把DrugBank的靶点跟UniProt的蛋白序列对齐,才发现RDF图有天然的URI机制,轻松多了。所以建议:如果你的数据需要频繁跨库融合,考虑RDF;如果以内部分析为主,属性图更快更好用。
5. 知识图谱核心逻辑图
下面这个图能帮你看清整个流程:从原始数据到三元组,再到图数据库。
这个图我画了好几次才找到合适的布局——左到右是数据流,从上到下是流程层。特别注意“三元组构建”这一步,它决定了图谱的质量。很多项目失败,不是因为算法不行,是因为三元组质量太差——实体对齐错了、关系定义模糊、层级混乱。我在这个环节吃过亏,你现在看到这段文字,就是血的教训。
6. 图数据库的查询实践
咱们动手看看。假设你有一个药物KG,里面存放了药物、靶点、通路、疾病之间的关联。我想查:“哪些药物可以通过抑制EGFR来治疗非小细胞肺癌?”
在Neo4j里这样写:
MATCH (drug:Drug)-[:TARGETS]->(gene:Gene {name: 'EGFR'}),
(drug)-[:TREATS]->(disease:Disease {name: '非小细胞肺癌'})
RETURN drug.name, drug.pubchem_cid
这个查询会走两条路径:
一条是“药物→靶点”,
另一条是“药物→疾病”。
我个人习惯还在返回值里带上药物的PubChem ID,方便后续交叉验证。
CREATE INDEX ON :Gene(name)
CREATE INDEX ON :Disease(name)
跑查询时,不用全图扫描,直接从索引定位到EGFR节点。
7. 总结一下
今天聊了三块内容:
- 三元组:知识的最小表达单元,标准化后可推理、可合并。
- 实体与关系:定义粒度决定了图谱的质量。别太粗也别太细。
- 图数据库:RDF图和属性图各有适用场景。跨库融合选RDF,内部查询选属性图。