第3章:知识图谱构建技术栈——我的“兵器库”
说实话,理论聊再多,不如直接把袖子撸起来干活。这一章,咱们来盘一盘真正要上手的家伙事儿。
工具选不对,后面全是泪。我用这些年踩过的坑跟你保证,选对技术栈,项目进度能快一倍。下面我把自己的“兵器库”摆出来,一个个给你讲透。
3.1 Neo4j:图数据库里的“老大哥”
如果你问我现在做知识图谱用啥最多,我会毫不犹豫选Neo4j。市场上图数据库不下几十种,Neo4j的使用率稳居第一。为什么?因为它真的“懂”开发者。
我记得刚入行那会儿,团队里还有人纠结用RDBMS还是图数据库。结果一个三跳查询下去,SQL写了三十行,Neo4j只需要三行Cypher,当场就把同事征服了。
你想想看,一个癌症药物知识图谱里,有药物、靶点、疾病、基因、临床试验……这些东西之间的关系错综复杂。用传统关系型数据库,各种JOIN表我都怕。但在Neo4j里,每个实体就是一个节点,关系就是边,直观得很。
安装方面,我建议下载桌面版(Neo4j Desktop),省心。命令行的玩法虽然更geek,但新手容易在环境配置上卡壳。
# 拉取Neo4j Docker镜像(我个人更推荐这种方式)
docker pull neo4j:5.12.0
# 启动容器,挂载数据目录和日志目录
docker run \
-d \
--name cancer-kg-neo4j \
-p 7474:7474 -p 7687:7687 \
-v /data/neo4j/data:/data \
-v /data/neo4j/logs:/logs \
-e NEO4J_AUTH=neo4j/cancerKG2024 \
neo4j:5.12.0
启动后,打开浏览器访问 http://localhost:7474,用你设置的密码登录。看到那个浏览器界面了吗?那就是你的主战场。写Cypher查询、可视化图谱、做数据探索,全在那里面完成。
conf/neo4j.conf里设好dbms.memory.heap.max_size,别偷懒。
3.2 RDF与SPARQL:标准化的“另一种活法”
聊完Neo4j,咱们得说说RDF。你可能听过一句话:知识图谱有两种流派,LPG(属性图)和RDF。我做项目时经常被问到“选哪个好?”我的回答是——看你场景。
RDF这玩意儿,说白了就是一种描述资源的框架。你用三元组(主语-谓语-宾语)来陈述事实。比如“吉非替尼治疗非小细胞肺癌”,在RDF里就写成:
<http://example.org/drug/gefitinib>
<http://example.org/property/treats>
"非小细胞肺癌" .
你看,这就是RDF最基础的样子。它的强项在于语义互操作性——数据之间能用URI打通。你在PubMed、DrugBank、ClinicalTrials.gov拿到的数据,转换成RDF后,天然就能融合。
而SPARQL,就是RDF世界的SQL。别看它语法有点怪,但查询能力是真的强。
举个场景:你想查所有作用于EGFR靶点的肺癌药物,以及对应的临床试验阶段。SPARQL写起来是这样的:
PREFIX drug: <http://example.org/kg/drug/>
PREFIX target: <http://example.org/kg/target/>
PREFIX disease: <http://example.org/kg/disease/>
PREFIX trial: <http://example.org/kg/trial/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?drugName ?trialPhase ?status
WHERE {
?drug rdf:type drug:Drug .
?drug drug:hasTarget target:EGFR .
?drug drug:treats disease:LungCancer .
?drug drug:hasTrial ?trial .
?trial trial:phase ?trialPhase .
?trial trial:status ?status .
?drug drug:name ?drugName .
}
这段查询返回的结果是:作用于EGFR的非小细胞肺癌药物,以及它们的临床试验阶段和状态。在真实项目中,这类查询能帮科学家快速锁定候选药物。
3.3 Python:黏合一切的“万能胶”
Python在知识图谱里扮演什么角色?我的理解是——没有它,上面的工具就是孤岛。
我个人习惯用Python来串联整个流程。数据采集用requests+BeautifulSoup,文本处理用spaCy,图谱操作用py2neo,最后还能用Flask搭个API露出来。一套下来,Python全包了。
环境配置我建议用conda,项目隔离做得好,不会出现莫名其妙的包冲突。下面是我常用的环境创建命令:
conda create -n cancer-kg python=3.10
conda activate cancer-kg
pip install neo4j py2neo spacy pandas requests lxml
python -m spacy download zh_core_web_sm
这里面有个容易忽略的点:spaCy的中文模型zh_core_web_sm只有几MB,做基础分词和命名实体识别够了。但如果你想做更精准的医学实体识别,建议用zh_core_web_trf(基于transformers),准确率能提5-8个点。
3.4 NLP工具链:文档里“挖金子”
癌症药物知识图谱的数据来源,大部分是PubMed摘要、FDA标签、临床试验报告。这些全是非结构化文本。如何把它们变成结构化知识?NLP就是你的挖掘机。
我主要用两套工具:
| 工具 | 适用场景 | 我的使用习惯 |
|---|---|---|
| spaCy | 中文文本处理、实体识别、依存分析 | 先训练一个医学领域NER模型,再批量跑PDF |
| StanfordNLP / Stanza | 英文文献分析、多语言联合 | 处理PubMed英文摘要时切换到它 |
举个实际例子。假设你有一篇文献说“Gefitinib demonstrates significant anti-tumor activity in NSCLC patients with EGFR mutations”。用spaCy处理,写出来大概这样:
import spacy
nlp = spacy.load("zh_core_web_sm")
# 实际项目中会自定义医学专用模型
# 这里以简单演示为主
text = "吉非替尼在携带EGFR突变的非小细胞肺癌患者中显示出显著的抗肿瘤活性"
doc = nlp(text)
for ent in doc.ents:
print(f"{ent.text} -> {ent.label_}")
输出结果应该是:
吉非替尼 -> DRUG
EGFR突变 -> GENE
非小细胞肺癌 -> DISEASE
你看,实体已经被打上标签了。这些标签后面会映射成图谱里的节点。DRUG、GENE、DISEASE就是我们图谱里的四种核心实体类型中的三种(再加上TRIAL)。
3.5 py2neo:Python操作Neo4j的“遥控器”
前面说了Neo4j、说了Python,怎么让它俩对话?py2neo就是我用的遥控器。
这个库封装了对Neo4j的各种操作。你不需要在浏览器里写Cypher,直接在Python脚本里就能完成图的创建、查询、删除。
我一般这样连接:
from py2neo import Graph, Node, Relationship
# 连接Neo4j数据库
graph = Graph(
"bolt://localhost:7687",
auth=("neo4j", "cancerKG2024")
)
# 创建两个节点
drug_node = Node("Drug", name="吉非替尼", mechanism="EGFR抑制剂")
trial_node = Node("Trial", name="NCT12345678", phase="III", status="已完成")
# 创建关系
rel = Relationship(drug_node, "HAS_TRIAL", trial_node)
# 写入图数据库
graph.create(rel)
print(f"创建成功:{drug_node} --[HAS_TRIAL]--> {trial_node}")
看到没?代码很简洁。Node创建节点,Relationship创建关系,最后用graph.create()提交。这里面有个细节——节点标签(Drug、Trial)最好跟你的本体设计保持一致。我曾在项目里换过一次标签命名规范,结果还要重新映射,被搞得很痛苦。
from py2neo.bulk import create_nodes, create_relationships
# 批量创建节点
drugs = [
("Drug", {"name": "吉非替尼", "mechanism": "EGFR抑制剂"}),
("Drug", {"name": "奥希替尼", "mechanism": "EGFR T790M抑制剂"}),
("Drug", {"name": "克唑替尼", "mechanism": "ALK抑制剂"}),
]
batch_size = 1000
create_nodes(graph, drugs, batch_size=batch_size)
3.6 技术栈俯瞰:一张图说清
上面这些工具各有分工。我把它们之间的关系画了张图,这样你看着更清楚:
这张图我把整个技术栈分成四层:数据来源一头扎进去,NLP工具负责“消化”成结构化信息,Neo4j和RDF负责“存储+查询”,最上面应用层把知识“吃”出来。Python就像一根管道,把每一层串在一起。
3.7 我的选型建议
说了这么多,你可能在纠结:到底用不用RDF?要不要上StanfordNLP?
我的建议很简单——看项目规模:
- 小项目(< 1万实体): 只用Neo4j + py2neo + spaCy 就够了。RDF可以先不考虑。
- 中型项目(1-10万实体): 加上StanfordNLP处理英文文献,py2neo批量写入。
- 大型项目(> 10万实体,多机构协作): 必须上RDF/OWL做语义互操作。SPARQL endpoint搭建好,方便外部调用。
我自己做癌症药物知识图谱时,起步阶段先用Neo4j快速建原型,等数据源稳定了,再导出RDF做标准化发布。两条腿走路,稳得很。