老城区有条“梧桐里”,住着三百户人家。王婶是这条街的“活地图”,谁家几口人、谁和谁是亲家、谁欠谁一个人情,她比谁都清楚。可最近,王婶也犯难了——光靠脑子记,已经理不清越来越密的邻里关系网。街道办决定用一台“电子信息簿”来承载这份庞大的人脉网,它就是 Neo4j。 但电子信息簿有个难题:王婶记性不好时,充其量是忘事;电子系统记错账,却是大事——张叔的帮扶积分凭空多了,李阿姨的关系被删掉了,那可会闹出矛盾。于是,这台电子信息簿不仅要能记录错综复杂的关系网(属性图模型),还要像银行账本一样严格:每次登记要么完整记下、要么完全不记,绝不允许“记一半丢一半”(ACID 事务)。这就是本篇文章的主角:Neo4j,一个既懂“关系”又讲“规矩”的图数据库。
对 AI 从业者来说,掌握 Neo4j 的属性图模型和 ACID 事务,意味着你既能用图结构承载知识图谱,又能保证数据在金融、合规等场景下“不出错、不丢失”——这是从“能跑通 Demo”迈向“能落地生产系统”的关键一步。
可视化演示
本节配有交互动效(进入视口后自动加载,约 3KB)。
细粒度锁:不同事务可并行访问不同节点 Neo4j属性图可视化:展示节点-关系图结构、ACID事务流程和锁机制
属性图模型
王婶的“人脉账”是怎么记的?每个居民一张小卡片(节点),卡片上贴着身份标签(如“志愿者”“独居老人”),写着个人资料(属性),比如年龄、职业、联系电话。卡片之间用彩色毛线连接,代表“认识”“帮助过”“是亲戚”等关系;每根毛线上还挂着一个小牌子,记录“什么时候认识的”“帮了什么忙”(关系属性)。这张由卡片和毛线织成的网,就是属性图模型。
在计算机世界里,属性图模型用数学语言表达为:
这就是属性图模型的核心:节点、关系、标签、属性四件套。关系不再像关系型数据库那样靠“外键 + 多表 JOIN”间接表达,而是被提升为“一等公民”,直接以边的形式存在。用 Neo4j 的查询语言 Cypher 写一条查询,就像王婶顺着一根毛线找人一样自然:先定位到某个标签的节点,沿着某个类型的关系边,就能把“张叔→认识→李阿姨”这样的路径瞬间找出来。
回到比喻:王婶之所以是“活地图”,是因为她的脑子里存的就是一张图——她从来不需要像翻花名册那样逐页查找“哪些人和张叔有关”,而是直接沿着关系的毛线走。属性图模型就是把这套“人脉思维”原封不动地搬进了计算机。
- V(Node 集合)代表图中所有节点的集合,对应社区里的每一位居民。每个节点都有一个唯一的标识符。
- E(Edge 集合)代表图中所有关系边的集合,对应居民之间的每一根毛线。每条边都有方向(从谁指向谁)和类型。
- L_v(节点标签)给节点分类的标签,如“Person(人)”“Volunteer(志愿者)”。一个节点可以有多个标签,方便快速筛选。
- L_e(关系类型)给边分类的类型,如“KNOWS(认识)”“HELPED(帮助过)”。关系类型让遍历时能精确选择要沿哪种边走。
- P_v(节点属性)挂在节点上的键值对集合,如 {name: “张叔”, age: 55}。属性是“卡片的文字内容”。
- P_e(关系属性)挂在边上的键值对集合,如 {since: 2020, date: “2025-06-01“}。它能描述”这段关系本身”的信息。
ACID事务特性
有一次,李阿姨帮张叔修好了水管,街道办要登记这笔“帮扶事件”。登记的动作包括:修改李阿姨的积分、添加一条“帮助过”的关系、更新张叔的“待还人情”备注。这看起来只是几笔改动,但王婶坚持要立下四条铁规矩——这四条规矩,就是 ACID。
第一条:原子性(Atomicity)。登记要么完整地记下所有步骤,要么一个字都不写。绝不能出现“积分加了,但关系没记上”的半截账。第二条:一致性(Consistency)。记完之后,账本必须仍然自洽——不存在“张叔的积分显示 0,但帮扶记录写着 +10”的矛盾。第三条:隔离性(Isolation)。两个文员同时登记不同事件时,谁也不能读到对方“写了一半还没写完”的临时数据。第四条:持久性(Durability)。一旦登记完成交到档案室,就算当晚停电、电脑死机,这笔记录也不能丢。
数学上,一个事务 T 是多个操作打包后的整体:
在 Neo4j 中,一条写事务执行多行 Cypher 语句时,引擎会自动把这些语句包裹进一个事务里。只要有一行语句报错,前面所有操作都会被回滚。这对于金融转账、权限变更、多步图谱更新等“一步错就会出大事”的场景,是至关重要的保护机制。
回看社区故事:ACID 让“登记帮扶”这个日常动作变得像银行转账一样严谨。王婶的账本从“口头记忆”升级成了“经过四条铁规矩检验的正式档案”,每笔记录都经得起追溯——这就是图数据库在严肃场景中的底气所在。
- op_i(单个操作)事务中的每一个原子操作,比如“修改李阿姨积分”“添加一条 HELPED 关系”。它们是构成事务的最小单位。
- {op1, ……, opn}(操作打包)把多个操作塞进同一个大括号里,代表它们被绑定为一个整体。这就是“原子性”的来源——打包后的操作序列不可分割。
- \implies(蕴含符号)表示“事务的结局只有一条路”。这等同于王婶说的“要么全记,要么全不记”。系统不允许停在中间状态。
- Commit(提交)所有操作成功,事务的修改正式对外可见。相当于登记表经过审核盖上“已归档”的章。
- \lor(逻辑或)二选一,非此即彼。这是“原子性”的数学表达:没有第三种“半提交”状态。
- Abort(回滚)任一操作失败,所有已执行的修改全部撤销,数据库恢复到事务开始前的样子。
锁机制并发
社区居委会的窗口前,文员们开始忙碌。问题来了:如果两个文员同时想修改张叔的卡片,一个要加积分,一个要改备注,两个人都握着笔去改,张叔的卡片就被写乱了。于是居委会定下规矩:桌上摆两种牌子——绿牌“正在阅读”和红牌“禁止触碰”。
绿牌对应计算机里的共享锁(Shared Lock):多个文员可以同时摆上绿牌、同时阅读同一张卡片,互不干扰。红牌对应排他锁(Exclusive Lock):一旦有人摆上红牌,其他任何人既不能读也不能写,直到红牌被收走(事务提交或回滚)。用矩阵可以清晰地表达这种兼容关系:
Neo4j 的锁是细粒度的,锁在具体的节点或关系上,而不是整张图加锁。这就像居委会只给“正在被修改的那一张卡片”摆红牌,其他三百户居民的事务完全不受影响,照常办理。同时,Neo4j 内置了死锁检测:假设文员 A 握着李阿姨的卡在等张叔的卡,文员 B 握着张叔的卡在等李阿姨的卡——两人互不相让,就僵住了。Neo4j 检测到这种循环等待后,会选一个事务作为“牺牲者”回滚,让它释放锁,另一个事务则正常完成。
回到比喻中,锁机制就是居委会桌上的绿牌和红牌。它保证了一百个窗口同时办事时,每张卡片都被改得清清楚楚、绝不混乱。社区秩序不是靠文员们的自觉,而是靠这套朴素的“挂牌”规则。
- S × S(共享锁遇上共享锁)结果是对勾,表示兼容。多个事务可以同时读取同一个节点,像多人同时翻看同一张公开告示。
- S × X(共享锁遇上排他锁)结果是叉,表示冲突。读的人还没看完,写的人就不能动笔,反之亦然。
- X × X(排他锁遇上排他锁)结果是叉,表示互斥。两个写事务绝不能同时修改同一个节点。
事务日志引擎
档案室还有一条更重要的规矩:任何人要修改正式账本,必须先在一本“流水草稿”上记一笔,核对无误后,才允许誊写到正式账本上。草稿本的存在,保证了一件事——即使正式账本被火烧了、被水淹了,只要草稿还在,就能照着流水一笔一笔重新誊写出来。这就是预写日志(Write-Ahead Logging, WAL)的核心思想:先写日志,再写数据。
日志记录了每个操作的事务 ID、数据页号、修改前后的值。系统每隔一段时间会做一次检查点(Checkpoint):把已确认的修改真正同步到数据文件,并在日志中标记“到这个位置为止都可以信任了”。这样,崩溃恢复时只需要从最近一次检查点往后重放日志,不必从第一天开始翻流水。
Neo4j 正是依靠 WAL 实现了崩溃恢复( Crash Recovery):数据库重启后,先检查日志,把已经提交但尚未写入数据文件的事务“重放”一遍,把未提交的事务“撤销”掉。社区里的“流水草稿”就是 Neo4j 的 WAL,“账目照片”就是检查点,“照着草稿重新誊写”就是崩溃恢复。有了这套机制,正式账本即使意外损坏,也能从草稿中完整还原,不必求助王婶的记忆。
- Write(Log)(写日志)事务的第一个动作是把修改操作追加到日志文件。日志是附加写入,就像流水账一笔接一笔,顺序写磁盘速度极快。
- \rightarrow(严格先后)箭头是“必须先完成”的意思。日志没写成功,数据绝对不允许先改。这是 WAL 铁律。
- Write(Data)(写数据)日志落盘后,才把修改应用到正式数据文件。此时即使系统崩溃,日志里也留下了修改证据。
一致性级别
随着社区事务越来越多,居委会开了两个服务窗口。不同窗口允许文员看到“数据状态”的规则不同,这就是一致性级别(Isolation Level)。三种递进的规则对应三种级别:读已提交(Read Committed)、可重复读(Repeatable Read)、序列化(Serializable)。
Neo4j 默认采用读已提交:文员只能读到已经正式提交的账目,绝不会看到另一个窗口“正在写但还没写完”的草稿——这避免了臭名昭著的“脏读”。但如果一个文员在整理报表期间多次翻看同一页,他可能因为别的窗口提交了新数据而看到前后不一致的内容,这就是读已提交的局限。更严格的可重复读,保证同一事务内多次读取同一数据结果不变。
集群模式下,Neo4j 还提供一种贴合实际语义的因果一致性(Causal Consistency)。用数学语言表达:
这条规则直观地对应了“发了消息立刻就能看到”的体验:用户在手机上的某个节点写了一条数据,然后立即查询,查询事务在因果顺序上晚于写事务,因此一定能读到刚才写入的数据。如果没有因果一致性,可能会遇到“明明提交成功了,刷新却看不到”的诡异现象——这在生产系统中是难以容忍的。
窗口的规则越严格,安全性越高,但效率会降低。Neo4j 的设计是在单机默认场景提供读已提交的轻量保障,在集群场景用因果一致性保证“因果不乱的错觉”,让程序员像使用单机数据库一样编写分布式应用。
- T₁ ≺ T₂(因果先序)事务 T₁ 在因果顺序上先于事务 T₂,比如 T₁ 提交后才发起 T₂。在社区里,就是“A 窗口先登记完,然后 B 窗口才开始工作”。
- \Rightarrow(蕴含)这是因果一致性的核心承诺——只要顺序如此,结果必须保证。
- Read(T₂) ⊇ Write(T₁)(可见性包含)T₂ 能读到的数据集合必须包含 T₁ 写入的数据。也就是说,T₁ 的成果不能对 T₂“隐身”。
GraphRAG融合
故事继续:街道办请来一个“智能助手小赵”。小赵厉害的地方在于,它不只是王婶那样的“人脉活地图”,也不只是普通的“语义词典”,它把两者结合了起来。它的左手有一张全社区的关系网(属性图),右手有一本“语义词典”(向量索引)。居民问小赵:“谁可能愿意帮独居的张叔修水管?”小赵会先沿着关系网找到张叔的邻居、朋友、互助小组成员,再从语义词典中找出描述过“帮忙修过水管”或“擅长水暖”的人,最后综合两路结果给出推荐。
这就是 GraphRAG(图增强检索生成):将知识图谱的结构化关系与大语言模型的语义理解结合起来。在 Neo4j 中,可以为节点或文本属性建立向量索引,并在一条 Cypher 查询中同时做图遍历和向量相似度检索,最终按融合得分排序返回答案:
GraphRAG 最擅长回答纯向量检索答不了的问题——“张工在哪个项目上与李工合作过?”这种问题涉及关系链,单纯靠文本匹配很难从零散文档中拼出完整答案;而如果只靠图遍历,又很难理解“合作过”这种语义变体。GraphRAG 让两者互补:先用向量找到候选,再用图做多跳验证,最后把路径信息作为上下文交给大模型生成回答。
小赵(智能助手)之所以比王婶更厉害,是因为它既有“人脉直觉”(图结构)又有“语义理解”(向量)。当它回答问题时,既有关系网的证据,又有语义的辅助,答案自然更加可靠——这就是 GraphRAG 在知识图谱落地中越来越受重视的原因。
- v_q(查询向量)把用户的自然语言问题转换成高维语义向量。这是用嵌入模型(如 text-embedding)把文字“翻译”成机器能理解的坐标。
- v_e(知识条目向量)把图数据库中的节点文本(如某个人的简介、某条记录的内容)也转换成相同空间的向量。
- cos(v_q, v_e)(语义相似度)计算两个向量的余弦值,范围从 -1 到 1。越接近 1,表示语义越相关。这是“语义词典”那一路的得分。
- graph(q, e)(图结构得分)计算查询与节点在图上的关联强度,比如最短路径长度、共同邻居数、关系类型的匹配度。这是“关系网”那一路的得分。
- α 与 β(融合权重)两个超参数,决定语义和结构哪个分量更重要。两者之和等于 1。
集群高可用
社区规模扩大,一个档案室的容量和可用性都跟不上了。街道办决定:西区设总站,东区设分站。总站负责登记新账目(写操作),分站则实时拿到一份账本的“复印件”,负责居民查询(读操作)。即使总站半夜停电,分站也能立刻拿出“备用公章”顶上去继续服务——这就是集群高可用。
在 Neo4j 企业版中,这套架构称为因果集群(Causal Clustering)。集群中有一个主节点(Leader),负责接收所有写操作;其余从节点(Follower)异步或半同步地复制主节点数据,同时对外提供读服务,这就实现了读写分离。写入时,主节点需要征求多数派节点的确认,才能向客户端返回“提交成功”:
当主节点发生故障(如断电、网络分区)时,集群会自动进行故障切换(Failover):剩余从节点中会选出一个新的主节点,继续接收写操作。应用层的驱动会自动感知拓扑变化,把新的写请求路由到新主节点,整个过程对客户端几乎无感。
回到社区:总站断电,分站顶上,居民们甚至感觉不到“档案室换地方了”。这就是高可用带来的安全感——数据永远在线,服务永不停机。不过要注意,集群复制并不等于备份,复制容易把“误删”也复制过去,这就需要下一节讲的备份恢复策略。
- w(写确认数)一次写提交需要至少多少个节点确认写入成功。在 3 节点集群中,w 通常设为 2(即多数派)。
- r(读参与数)一次读操作需要至少从多少个节点读取数据以保证读到最新值。和 w 配合使用。
- N(集群总节点数)集群中核心节点的总数。3 节点集群 N=3,5 节点集群 N=5。
- w + r > N(多数派条件)写节点数与读节点数之和必须超过总节点数。这保证了读写路径必然有重叠,从而读操作一定能遇到“知道最新数据”的节点。
备份恢复
即使有了集群和分站,街道办依然不敢掉以轻心——万一卷宗失火、档案室进水,复制再多也白搭。于是档案室制定了三级防护:全量备份(每周把整本账完整抄录一份)、物理备份(每天深夜将账本文件复制进保险柜)、增量备份(每小时记录新增和修改的页码)。灾难发生时,用“最近一次保险柜复印件 + 之后的小时记录”就能把数据恢复到出事的几分钟前。
在 Neo4j 中,备份分为两大流派:一是逻辑备份,用 Cypher 语句把节点和关系导出为文件(如 JSON 或 Cypher 脚本),跨版本兼容性好,但恢复时需要重新执行导入,速度较慢;二是物理备份,直接复制底层数据文件(如使用 neo4j-admin database dump 命令),恢复时把文件放回原位即可,速度接近“文件拷贝”的极限。两者通常配合使用:每周一次全量物理备份,每小时做一次增量备份。
衡量备份效果有两个关键技术指标:RPO(恢复点目标) 和 RTO(恢复时间目标):
社区的备份策略告诉我们一个重要的道理:备份不是“事后补救”,而是“日常功课”。每周的抄录、每天的复印、每小时的记录,看上去繁琐,却是在为“万一”做准备。Neo4j 管理员的生产最佳实践,通常是在集群外再配置一个定期备份任务,把备份文件存储到异地——因为集群内部的复制,解决不了“整栋楼被雷劈”的场景。
- T_failure(故障时刻)灾难发生的那一刻,比如档案室起火的时间点。
- T_last_backup(上次备份时刻)最近一次成功备份完成的时间。RPO 就是“上次备份”到“故障”之间隔了多久。
- RPO(恢复点目标)允许丢失的数据量对应的时间长度。如果每小时做一次增量备份,RPO 最多是 1 小时;如果每周做一次全量备份,RPO 可能长达 7 天。
- T_recovery(恢复完成时刻)从开始恢复到系统恢复对外服务的时间点。RTO 衡量的是“业务中断多久”。
- RTO(恢复时间目标)从灾难发生到恢复服务所花的总时间。物理备份恢复快,RTO 小;逻辑备份需要重建索引,RTO 大。
AI 应用场景
金融反欺诈知识图谱
阶段:特征工程与图特征提取
解决的问题:传统反欺诈系统用规则引擎一一匹配,难以发现跨多跳的关联欺诈。比如“张三的账户在 3 小时内转账给李四,李四又转给王五,而王五的卡曾关联过黑名单账户”,这类复杂关系在关系型数据库里需要多次 JOIN,性能差且逻辑繁琐。AI 模型需要的是“账户之间的资金流转图”作为输入特征。
具体案例:某股份制银行在 Neo4j 中存储 1000 万个账户及其转账关系,采用属性图模型建模,每笔交易以 ACID 事务写入,确保对账分毫不差。反欺诈团队利用 Cypher 查询提取“二跳以内的资金链路”作为图特征,喂给 XGBoost 模型做实时评分。每当模型发现可疑账户,系统会先锁定(排他锁)该账户节点,更新风险标签并持久化,整个过程由事务保证不会出现“打了标记却查不到”的状态。GraphRAG 还被用来结合黑名单样本生成风险解释报告,辅助人工审核。
企业知识库 + GraphRAG 智能问答
阶段:增强检索生成(RAG)的检索阶段
解决的问题:传统 RAG 只做向量相似度检索,无法回答“张工在哪个项目上与李工合作过,该项目的技术栈是什么”这类强关系问题。纯向量检索得到的片段往往缺乏实体之间的结构化关联,大模型回答容易“一本正经地胡说八道”。
具体案例:某大型制造企业将内部项目文档、人员档案、协作关系导入 Neo4j,同时为每个项目和人员的简介建立向量索引。员工在内部问答系统输入“张工最近参与的项目用了什么数据库”,系统先通过向量检索找到“张工”和候选项目节点,再在图谱上沿“参与过”关系遍历到项目,并把项目属性、团队成员作为上下文一并交给大模型,最终生成带引用依据的准确回答。写入项目数据的操作全部走 ACID 事务,保证多人同时录入时图谱不会出现“半条关系”。
Python 演示
"""极简图数据库: 属性图模型与 ACID 事务模拟"""import copy class MiniGraph: """极简属性图: 节点字典 + 关系列表""" def __init__(self): self.nodes = {} # node_id -> {label, props} self.rels = [] # {source, target, type, props} def add_node(self, node_id, label, props): self.nodes[node_id] = {"label": label, "props": dict(props)} def add_rel(self, source, target, rel_type, props=None): if source not in self.nodes or target not in self.nodes: raise ValueError("node not found") self.rels.append({ "source": source, "target": target, "type": rel_type, "props": dict(props or {}), }) class Transaction: """模拟 ACID 原子性: 用快照实现全做或全不做""" def __init__(self, graph): self.graph = graph self.snapshot = None def __enter__(self): # 事务开始: 给整张图拍一张快照 self.snapshot = copy.deepcopy(self.graph.__dict__) print(">> txn begin, snapshot created") return self.graph def __exit__(self, exc_type, exc_val, exc_tb): if exc_type is not None: # 有异常: 回滚到快照 self.graph.__dict__.clear() self.graph.__dict__.update(copy.deepcopy(self.snapshot)) print(">> txn abort, all changes rolled back") return False # 异常继续向上抛 print(">> txn commit, all changes applied") return True def main(): g = MiniGraph() g.add_node("zhang", "Person", {"name": "张叔", "age": 55, "points": 0}) g.add_node("li", "Person", {"name": "李阿姨", "age": 60, "points": 0}) g.add_rel("zhang", "li", "KNOWS", {"since": 2020}) print("init: rels =", len(g.rels), ", li.points =", g.nodes["li"]["props"]["points"]) # 场景1: 登记时网络中断, 事务应回滚 try: with Transaction(g) as tx: tx.nodes["li"]["props"]["points"] += 10 tx.add_rel("li", "zhang", "HELPED", {"date": "2025-06-01"}) raise RuntimeError("network down") except RuntimeError as e: print("business error:", e) print("after rollback: rels =", len(g.rels), ", li.points =", g.nodes["li"]["props"]["points"]) # 场景2: 一切正常, 事务提交 with Transaction(g) as tx: tx.nodes["li"]["props"]["points"] += 10 tx.add_rel("li", "zhang", "HELPED", {"date": "2025-06-01"}) print("after commit: rels =", len(g.rels), ", li.points =", g.nodes["li"]["props"]["points"]) if __name__ == "__main__": main()
self.nodes = {}用字典存储所有节点,键是节点 ID,值是标签和属性。这对应属性图模型中的 V(节点集合)。self.rels = []用列表存储所有关系,每条关系含 source、target、type、props。这对应 E(关系集合),关系是一等公民,可独立携带属性。copy.deepcopy(self.graph.__dict__)事务开始时给整张图做一份深拷贝快照。作用相当于 WAL 日志的“起点标记”,保证回滚时能还原。self.graph.__dict__.clear()回滚时清空当前图的全部数据。self.graph.__dict__.update(copy.deepcopy(self.snapshot))用快照恢复图的完整状态,实现“撤销所有修改”。return False让异常继续向上抛,由调用方处理。对应 Neo4j 中事务失败后由客户端收到异常通知。tx.nodes["li"]["props"]["points"] += 10在事务内直接修改节点属性。如果事务回滚,这行修改会被撤销。tx.add_rel("li", "zhang", "HELPED", ...)在事务内添加关系边。同样,回滚后这条关系不会出现在图中。
常见误区
误区
正解
误区
正解
误区
正解
误区
正解
误区
正解
面试题
Q1. 在 Neo4j 属性图模型中,“关系”与关系型数据库的外键最本质的区别是什么?
- A.关系数据库的外键速度更快
- B.图模型中的关系是一等公民,可携带属性且遍历高效← 正确答案
- C.外键可以表示多对多,图关系只能表示一对多
- D.图模型的关系不需要方向
答案:B。属性图模型中,关系是物理存储的一等公民,有方向、有类型、可携带属性,遍历边的时间复杂度是 O(1)。外键则需要在查询时通过 JOIN 计算关系。A 错误——图遍历通常更快;C 错误——两者都能表示多对多;D 错误——图关系是有方向的。
Q2. ACID 中的"A"代表什么?
- A.Availability 可用性
- B.Atomicity 原子性← 正确答案
- C.Authentication 认证
- D.Architecture 架构
答案:B。ACID 是 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)的缩写。A 是 CAP 定理中的概念,不要混淆。原子性保证事务中的操作要么全部提交、要么全部回滚。
Q3. Neo4j 默认的隔离级别是什么?
- A.读未提交
- B.读已提交← 正确答案
- C.可重复读
- D.序列化
答案:B。Neo4j 默认使用读已提交(READ_COMMITTED),事务只能读到已经提交的数据,避免脏读。可重复读和序列化是更严格的级别。读未提交是最松的级别,Neo4j 不采用。
Q4. 关于 Neo4j 的排他锁(X Lock),以下说法正确的是?
- A.多个事务可以同时持有同一节点的排他锁
- B.排他锁在该事务提交或回滚后才释放← 正确答案
- C.排他锁只阻塞写操作不影响读操作
- D.排他锁是全局锁,锁住整个数据库
答案:B。排他锁是事务级的,持锁事务结束(提交或回滚)时释放,期间其他事务的读写都会被阻塞。A 错误——排他锁互斥;C 错误——排他锁也阻塞读;D 错误——Neo4j 的锁是细粒度的,锁定在具体节点或关系上,不是全局锁。
Q5. WAL(预写日志)的核心原则是?
- A.先写数据再写日志,提高写入速度
- B.先写日志再写数据,保证崩溃后能恢复← 正确答案
- C.日志和数据同时写入,互不等待
- D.日志只记录查询语句,不记录修改
答案:B。WAL 要求日志必须先于数据落盘。修改数据前先写日志,这样即使系统崩溃,也能根据日志重放已提交事务、回滚未提交事务。A 是反的;C 和日志异步写入的机制不同;D 错误——日志记录的是修改操作而非查询。
Q6. Neo4j 因果集群中,主节点和从节点各自承担什么职责?
- A.主节点只读,从节点只写
- B.主节点负责写,从节点负责读(读写分离)← 正确答案
- C.所有节点既可以读也可以写
- D.从节点负责写,主节点只读
答案:B。Neo4j Causal Clustering 中,主节点(Leader)接收所有写操作,从节点(Follower)通过复制机制同步数据并对外提供读服务,实现读写分离。这样写有单一入口保证一致性,读可以水平扩展提升吞吐量。
Q7. GraphRAG 相比传统向量 RAG 的核心优势是什么?
- A.不需要向量索引,省存储空间
- B.能利用实体间关系进行多跳推理← 正确答案
- C.完全不需要大语言模型参与
- D.可以替代知识图谱手动构建
答案:B。GraphRAG 将知识图谱的结构化关系与向量语义检索结合,能回答“张工在哪个项目上与李工合作过”这类关系推理问题,而传统 RAG 只能做文本相似度匹配。A 错误——GraphRAG 同样需要向量索引;C 错误——生成阶段仍需要大模型;D 错误——知识图谱仍需要构建。
Q8. 属性图模型 G=(V,E,Lv,Le,Pv,Pe) 中,Pe 表示什么?
- A.节点的属性集合
- B.关系类型的集合
- C.关系上携带的属性集合← 正确答案
- D.图的路径集合
答案:C。Pe 是定义在边集合 E 上的属性映射,表示关系边自身携带的键值对属性,如 {since: 2020}。Pv 才是节点属性集合;Lv 是节点标签集合;Le 是关系类型集合。关系可携带属性是图模型的标志性特征。
Q9. 关于 Neo4j 的 ACID 事务,以下哪些说法是正确的?
- A.原子性保证事务操作全部提交或全部回滚← 正确答案
- B.一致性保证数据库始终满足完整性约束← 正确答案
- C.隔离性保证并发事务之间互不干扰← 正确答案
- D.持久性保证数据只保存在内存中
答案:ABC。A、B、C 分别是原子性、一致性、隔离性的正确定义。D 错误——持久性要求数据写入非易失性存储(磁盘),而不是只放内存,否则断电即丢。
Q10. Neo4j 企业版集群提供哪些高可用能力?
- A.主从复制与因果一致性← 正确答案
- B.读写分离与扩展读能力← 正确答案
- C.故障自动切换与恢复← 正确答案
- D.自动水平分库分表
答案:ABC。Neo4j Causal Clustering 提供主从复制(A)、读写分离(B)和自动故障切换(C)。但 Neo4j 官方不提供透明的水平分库分表(sharding)能力,大规模扩展通常需要应用层按业务维度拆库,D 错误。