Neo4j 实现原理
Neo4j 是原生图数据库,专注于存储和查询图结构数据。理解 Neo4j 的实现,需要深入图数据模型、存储引擎、索引机制和 Cypher 查询语言。
图数据模型
标签属性图
Neo4j 使用标签属性图模型,包含:节点(Node)、关系(Relationship)、属性(Property)、标签(Label)、路径(Path)。
节点是实体,可以有多个标签和多个属性。关系是节点之间的有向边,必须有一个类型(Type)和至少两个属性(起始节点 ID、结束节点 ID),也可以有其他属性。属性是键值对,值可以是原始类型或数组。标签是节点的分类,一个节点可以有多个标签。路径是节点和关系的交替序列。
图建模原则
关系数据库通过外键建模关系,查询需要多次 JOIN。图数据库直接存储关系,查询可以遍历关系。例如查询"朋友的朋友",关系数据库需要多次自 JOIN,图数据库只需要两次关系跳转。
避免超级节点(super node):度数很大的节点会遍历大量关系,性能差。例如"所有人关注 Twitter",该节点的度数是用户数,遍历开销大。解决方案:将时间、分类等维度加入关系,减少度数。
存储引擎
节点和关系存储
Neo4j 将节点和关系分开存储。节点存储包含:节点 ID、标签、属性 ID、关系的第一个 ID 和第二个 ID(用于双向遍历)。关系存储包含:关系 ID、类型、属性 ID、起始节点 ID、结束节点 ID、前一个关系 ID、下一个关系 ID(用于起始节点的关系链)、前一个关系 ID、下一个关系 ID(用于结束节点的关系链)。
节点的关系链组织成一个双向链表,通过起始节点的关系 ID 可以遍历所有关系。关系链是双向的,可以正向和反向遍历。
属性存储
属性存储在属性链中,每个属性是一个键值对。同一个节点或关系的属性链式组织,通过属性 ID 链接。属性值可以是原始类型或数组,数组的每个元素存储在单独的记录中。
属性存储是独立的,节点和关系只存储属性 ID,通过属性 ID 查找属性。这种设计避免了重复存储属性,但增加了查找开销。
固定大小记录
Neo4j 的存储记录是固定大小的,便于内存映射和缓存。节点记录 9 字节,关系记录 33 字节,属性记录 41 字节。固定大小记录可以直接通过 ID 计算 offset,支持 O(1) 访问。
缓存
Neo4j 使用两层缓存:页面缓存(Page Cache,缓存数据页)和对象缓存(Object Cache,缓存节点和关系对象)。页面缓存是操作系统的文件缓存,使用 mmap 映射文件到内存。对象缓存是 Neo4j 的缓存,缓存热点的节点和关系。
索引
Schema 索引
Schema 索引是用户显式创建的索引,支持单个属性或多个属性(复合索引)。索引类型:btree(默认,支持范围查询)、fulltext(全文检索)、point(空间索引)。索引通过 Cypher 创建:CREATE INDEX ON :Person(name)。
Schema 索引加速查找:WHERE name = 'Alice' 会使用 name 索引快速定位节点。索引会自动维护,插入、更新、删除节点时更新索引。
全文索引
全文索引基于 Apache Lucene,支持文本搜索。全文索引需要显式创建:CREATE FULLTEXT INDEX FOR (n:Person) ON EACH [n.name]。全文索引支持 CONTAINS、STARTS WITH 等查询。
自动索引
Neo4j 早期版本有自动索引,为每个标签的每个属性自动创建索引。自动索引已废弃,建议使用 Schema 索引。
约束
约束是特殊的索引,保证数据唯一性或存在性。唯一约束:CREATE CONSTRAINT ON (p:Person) ASSERT p.id IS UNIQUE。存在性约束:CREATE CONSTRAINT ON (p:Person) ASSERT exists(p.name)。约束可以加速查找,同时保证数据完整性。
Cypher 查询语言
查询结构
Cypher 是声明式图查询语言,类似于 SQL 的图版本。查询结构:MATCH(模式匹配)、WHERE(过滤)、RETURN(返回结果)、ORDER BY(排序)、LIMIT(限制)、SKIP(跳过)。
模式匹配
Cypher 的核心是模式匹配(Pattern Matching),使用 ASCII 图表示节点和关系。例如:MATCH (p:Person)-[:KNOWS]->(f:Person) WHERE p.name = 'Alice' RETURN f.name 表示查找 Alice 认识的人。
模式匹配支持:变长关系(-[:KNOWS*1..3]->,1 到 3 跳)、最短路径(shortestPath)、任意路径(allShortestPaths)。
查询执行
Cypher 查询执行经历:解析成逻辑计划、优化逻辑计划、生成物理计划、执行物理计划。优化器基于规则(RBO)和成本(CBO),考虑索引、选择性、查询模式。
物理计划包含多个算子:NodeByIndexScan(索引扫描节点)、NodeByLabelScan(标签扫描节点)、Expand(展开关系)、Filter(过滤)、Projection(投影)、Sort(排序)。
查询优化
使用索引加速查找:WHERE name = 'Alice' 应该在 name 上创建索引。避免笛卡尔积:MATCH (a:A), (b:B) 会产生 A 和 B 的笛卡尔积,应该使用关系连接:MATCH (a:A)-[:REL]->(b:B)。
使用 PROFILE 查看执行计划,分析性能瓶颈。使用 EXPLAIN 查看执行计划,不实际执行查询。
高可用
###因果集群
Neo4j 企业版支持因果集群(Causal Cluster),包括核心服务器(Core Server)和只读副本(Read Replica)。核心服务器使用 Raft 协议复制数据,保证强一致性。只读副本异步复制数据,可以处理读请求。
备份与恢复
Neo4j 支持全量备份和增量备份。全量备份复制整个数据目录,增量备份复制事务日志。恢复时,先恢复全量备份,然后重放事务日志。
Neo4j 是专业的图数据库,适合社交网络、知识图谱、欺诈检测等场景。理解它的实现,有助于设计图模型、优化查询和规划集群架构。