2. 图数据库选型:Neo4j、JanusGraph、ArangoDB 对比与选择
图数据库选型这件事,说实话没少让我头疼。早年我带团队做药物知识图谱,一开始拍脑袋选了某个库,结果查询延迟暴增,运维成本翻倍。后来被迫迁移数据,那滋味可不好受。所以这一章我结合实战经验,把几个主流图数据库掰开揉碎讲清楚。
2.1 三大主流图数据库概览
目前药物图谱场景中用得最多的,就是 Neo4j、JanusGraph 和 ArangoDB。它们各有擅长的地盘,没有银弹。
| 特性 | Neo4j | JanusGraph | ArangoDB |
|---|---|---|---|
| 存储引擎 | 本地 Native 存储 | 后端可插拔(HBase/Cassandra/BerkeleyDB) | 自研多模型存储 |
| 查询语言 | Cypher(原生属性图) | Gremlin(遍历式) | AQL(类 SQL + 图遍历) |
| 分布式 | 企业版集群,社区版单机 | 原生分布式(依赖外部存储) | 多活集群,强一致性 |
| 事务支持 | ACID 完整 | 取决于后端存储 | ACID(单节点);集群弱化 |
| 部署复杂度 | 极低(开箱即用) | 高(需搭 Hadoop/大数据栈) | 中(自带集群管理) |
| 典型规模 | 百亿节点以内 | 千亿级,海量数据 | 百亿节点,混合模型 |
单看表格可能不够直观。我来拆解一下每个库在真实药物图谱项目里的表现。
2.2 Neo4j:快速原型与中等规模首选
我个人习惯把 Neo4j 当作「图数据库中的 MySQL」。安装简单,社区活跃,Cypher 查询写起来很顺手。
我曾经接手一个药物-靶点-疾病关联图谱,一开始只有 500 万节点、2000 万关系。用 Neo4j 社区版,单机部署,索引优化好之后,跳数查询基本在 50ms 以内。团队里新来的实习生两天就能上手写 Cypher。
但注意一个坑——写入瓶颈。Neo4j 单机写入受限于磁盘 I/O,批量导入可以用 neo4j-admin import,但如果你的业务需要高频实时写入,千万要小心。
典型的 Cypher 写法:
// 查询某个药物作用的靶点,再跳转到相关疾病
MATCH (d:Drug {name: '阿司匹林'})-[:TARGETS]->(t:Target)
OPTIONAL MATCH (t)-[:INVOLVES]->(dis:Disease)
RETURN d.name, t.name, dis.name
LIMIT 100
这个查询在索引命中的情况下,亿级数据也能秒出。但如果你做了全表扫,那就要命了——所以我建议生产环境一定要给所有查询字段建索引。
2.3 JanusGraph:海量数据的硬核选择
如果你的药物图谱达到百亿节点级别,并且需要分布式横向扩展,那 JanusGraph 值得认真考虑。它本身不存数据,数据放在 HBase 或 Cassandra 里,计算层可以水平扩展。
但老实说,部署门槛真不低。我记得第一次搭 JanusGraph 集群,光是调通 HBase + Elasticsearch(索引后端)就花了一周。要是团队里没有懂 Hadoop 生态的人,我建议先评估一下成本。
# JanusGraph 配置示例(conf/gremlin-server.yaml)
host: 0.0.0.0
port: 8182
graphs: {
graph: conf/janusgraph-hbase.properties
}
scriptEngines: {
gremlin-groovy: {
plugins: {
org.janusgraph.graphdb.tinkerpop.plugin.JanusGraphGremlinPlugin: {}
}
}
}
g.V().has('Drug', 'name', '阿司匹林')
.out('TARGETS').hasLabel('Target')
.out('INVOLVES').hasLabel('Disease')
.valueMap('name')
Gremlin 的遍历式思维需要适应一阵子。我团队里不少开发习惯用 Cypher,切到 Gremlin 后写错了两周才上手。所以选型时也要考虑团队技术栈。
2.4 ArangoDB:多模型灵活性
ArangoDB 比较特殊——它不但是图数据库,还是文档数据库和 KV 存储。如果你在药物图谱里需要同时存结构化表格数据、JSON 文档和图关系,ArangoDB 可以一张表搞定。
它的 AQL 查询语言有点像 SQL 加图遍历,我团队里做后端的人学起来很快。但 ArangoDB 的图遍历性能在深度跳数时会有衰减,实测 6 跳以上就不如 Neo4j 了。
// AQL 查询:药物→靶点→疾病
FOR d IN Drug
FILTER d.name == '阿司匹林'
FOR t IN OUTBOUND d TARGETS
FOR dis IN OUTBOUND t INVOLVES
RETURN {drug: d.name, target: t.name, disease: dis.name}
2.5 选型决策框架
说了这么多,到底怎么选?我总结了几个问题,你对照着问自己就行:
- 数据规模多大? 十亿以下 → Neo4j;百亿以上 → JanusGraph;中间态 → 看其他因素。
- 团队会什么? 会 Cypher → Neo4j;会 Gremlin → JanusGraph;会 SQL → ArangoDB 门槛最低。
- 需要事务吗? 强 ACID → Neo4j 或单机 ArangoDB;最终一致可接受 → JanusGraph。
- 部署运维成本? 没人运维 → Neo4j 社区版;有专职 DBA → JanusGraph;折中 → ArangoDB。
下面这张图总结了三者的决策路径:
2.6 我的最终建议
如果你现在让我给药物图谱项目做选型,我会这么干:
- 第一阶段(原型验证):无脑上 Neo4j 社区版,用 Docker 5 分钟跑起来。快速验证查询逻辑和数据模型。
- 第二阶段(生产上线):如果数据量在 5 亿节点以内,且不需要分布式,继续用 Neo4j 企业版,花钱买省心。
- 第三阶段(海量扩展):数据超过 20 亿节点,或者需要多机房部署,迁移到 JanusGraph。嗯,迁移过程很痛苦,所以一开始就要留好数据导出接口。
- 特殊情况(混合模型):如果图谱里混着很多半结构化的临床文档,同时又要做图分析,直接上 ArangoDB 一张表搞定。
选型没有标准答案,但有一条铁律:不要为了技术而技术。选团队最熟悉、运维成本最低、能满足三年内数据增长的方案,通常就是最优解。