知识图谱基础概念与架构
说实话,很多人一听到“知识图谱”就觉得是高大上的黑科技。我刚开始入行时也这么想,直到亲手搭了一套药物知识图谱,才发现它本质上就是个组织信息的工具。只不过这个工具比较聪明——它能理解实体之间的关系。
你能想象吗?传统的数据库里,“布洛芬”和“退烧”可能是两条毫无关联的记录。但在知识图谱里,它们之间有一条明确的线:“布洛芬 ➝ 用于治疗 ➝ 退烧”。这就是质的区别。
为什么药物行业需要知识图谱?
我遇到过不少药企的朋友,他们拿着堆成山的Excel、PDF文档,里面全是药品信息、临床试验数据、不良反应报告。数据在那,但查起来费劲——你想知道“阿司匹林和哪些药冲突”,得翻半天文档。
知识图谱把这一切串联起来。
- 打通信息孤岛:化学结构、适应症、副作用、用药禁忌……原本分散在不同部门的数据,现在可以在图谱里自由穿行
- 支持智能推理:比如A药含有成分B,B与C有相互作用,图谱能自动推演出A和C不能同服,这些在传统数据库里需要写复杂的JOIN
- 质控可追溯:每个节点、每条关系都有源头,哪条数据出问题了,能一路追查到原始文献
核心概念:实体、关系、属性
知识图谱的基础其实特别简单,就三样东西:实体、关系、属性。说白了,就是“什么”和“什么”之间“有什么关系”。
| 概念 | 类比数据库 | 药物例子 |
|---|---|---|
| 实体 / 节点 | 表中的一行记录 | “布洛芬”、“发热”、“默克公司” |
| 关系 / 边 | 外键 + 业务含义 | “布洛芬” ➝ 用于治疗 ➝ “发热” |
| 属性 | 列字段值 | “布洛芬”的分子量 = 206.28 |
你可以把实体想象成城市地图上的地标,关系就是连接它们的道路。属性则是每个地标的详细信息:这家医院的床位数量、那家药企的成立年份。
三元组:图谱的最小存储单元
知识图谱里,每条知识都被拆成一个三元组:(头实体, 关系, 尾实体)。这玩意儿太重要了,我写质控脚本时,80%的工作就是在折腾三元组。
# 三个真实药物三元组示例:
(阿司匹林, 治疗, 头痛)
(阿司匹林, 包含成分, 乙酰水杨酸)
(乙酰水杨酸, 禁忌合并, 华法林)
为什么会这样设计?你想想看,当所有知识都统一成三元组后,无论多复杂的查询,都变成了在图里找路径。系统不需要理解“禁忌合并”这个词到底什么意思,它只负责找到这条边,然后顺着走。
Schema:给图谱定规矩
光有数据不行,你总得告诉系统:药物的关系只能是“治疗”、“副作用”、“禁忌”这几种,不能乱写“药物爱生病”吧?
Schema就是干这个的——它定义了哪些实体类型允许存在,哪些关系类型可以使用。
# 知识图谱模式(schema)示例
实体类型: Drug, Disease, Symptom, Company, Ingredient
关系类型:
- (Drug) --[treats]--> (Disease)
- (Drug) --[has_ingredient]--> (Ingredient)
- (Drug) --[side_effect]--> (Symptom)
- (Drug) --[contraindicated_with]--> (Drug)
- (Drug) --[manufactured_by]--> (Company)
我曾经接手过一个图谱项目,之前的团队没定好Schema,结果“布洛芬”这个节点既当药品又当公司名,查出来的数据乱七八糟。从那以后,我每次做质控,第一件事就是拉Schema出来核对。
主流知识图谱架构
实际项目中,架构通常分四层。我画了一张图帮你看明白:
关键技术栈
我平时做药物知识图谱,技术栈大致长这样。给大家列个清单参考:
| 分层 | 常用工具 | 我的推荐理由 |
|---|---|---|
| 数据获取 | Scrapy, SpaCy, BERT | SpaCy的中文NER模型对药物名识别效果不错 |
| 存储 | Neo4j, ArangoDB, RDF4J | Neo4j社区活跃,文档齐全,适合快速验证 |
| 查询 | Cypher, SPARQL | Cypher上手快,SPARQL适合标准RDF |
| 推理 | Apache Jena, OWL API | Jena的推理器比较稳,大项目我选它 |
| 质控 | 自定义pipeline + 规则引擎 | 这部分我们后面会重点讲 |
一个真实的Cypher查询示例
假设你现在要查“哪些药物和布洛芬有相互作用”,在传统数据库里你要写三四个表连接。但在图数据库里很简单:
// 查找与布洛芬有相互作用的所有药物
MATCH (d:Drug {name: '布洛芬'})-[r:interacts_with]-(other:Drug)
RETURN other.name AS 药物名称,
r.detail AS 相互作用详情,
r.severity AS 严重程度
ORDER BY r.severity ASC
这段代码跑的很快。我见过最复杂的一个查询,跨了八个实体类型、十二条关系,Cypher写了二十几行,但执行时间还不到一秒。这就是图谱的威力——数据之间有路,不需要全表扫描。
Schema设计和质控的关系
嗯,这里要注意。很多人以为质控是数据落库之后才做的事,大错特错。质控从Schema设计就开始了。
我举个真实的坑。某个项目里,Schema给“药物”定义了“副作用”关系,但没规定目标实体类型。结果有人把“发热”写成了症状节点,有人写成了疾病节点,还有人写成了一串字符串字段。批次质控的时候气死我了,花了三天才把这些问题归拢好。
我个人习惯:设计Schema时,每个关系都明确标注目标实体类型,并且写好校验逻辑。比如 (Drug)-[side_effect]->(Symptom),就不允许指向 Disease 类型。
什么是好的知识图谱?
总结几个评判标准,都是我多年踩坑总结出来的:
- Schema整洁:实体类型不宜超过20种,关系类型不宜超过50种
- 实体唯一:同一个药物不能出现两个不同的节点,别名通过属性或关系处理
- 关系有源头:每条三元组都记录了来源文献或数据库ID,方便追溯
- 版本可追溯:每次更新都有记录,能回滚到任意历史版本
心里有了这些标准,你才敢说“我知道我手里的图谱是干净的”。我们后续所有的批次质控流程,都是围绕着这些核心概念展开的。