3.1 CREATE 与 MERGE:让图谱安全生长


文档摘要

3.1 CREATE 与 MERGE:让图谱安全生长 本节摘要:写入侧的第一道分水岭是 CREATE 与 MERGE 的语义差异:前者无条件新建,后者"确保存在"。本节给出两者各自的使用场景,重点拆解 MERGE 的锚定规则——锚错属性是重复节点的头号来源——并示范 ON CREATE/ON MATCH 分支与约束兜底的组合拳。读完后你的写入语句将具备幂等性。 第 2 章的图只读不长。本节开始让图生长,先立一条纪律:生产环境的写入默认用 MERGE,CREATE 只用于确定"这一定是新实体"的场合。理由在本节的案例里会变得很具体。

3.1 CREATE 与 MERGE:让图谱安全生长

本节摘要:写入侧的第一道分水岭是 CREATE 与 MERGE 的语义差异:前者无条件新建,后者"确保存在"。本节给出两者各自的使用场景,重点拆解 MERGE 的锚定规则——锚错属性是重复节点的头号来源——并示范 ON CREATE/ON MATCH 分支与约束兜底的组合拳。读完后你的写入语句将具备幂等性。

第 2 章的图只读不长。本节开始让图生长,先立一条纪律:生产环境的写入默认用 MERGE,CREATE 只用于确定"这一定是新实体"的场合。理由在本节的案例里会变得很具体。

一、CREATE:无条件新建

// 每执行一次,图里就多一个节点——哪怕内容一模一样 CREATE (p:Person {name: 'Alice', age: 30}) RETURN p
执行两次后: MATCH (p:Person {name: 'Alice'}) RETURN count(p) → 2 -- 两个独立的 Alice,没有唯一 id,人工无从区分

CREATE 同时也可以建关系,但要求两个端点已经匹配到:

// 两段式:先锚定两端,再连边 MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'}) CREATE (a)-[:KNOWS {since: 2023}]->(b)

二、MERGE:先查后建,确保存在

MERGE 的语义是"这个模式要么已存在,要么现在创建":

// 幂等:跑一百遍,图里也只有一个 Alice MERGE (p:Person {name: 'Alice'}) ON CREATE SET p.created = datetime() ON MATCH SET p.lastSeen = datetime() RETURN p

第一次执行走 ON CREATE 分支打上创建时间;之后再跑走 ON MATCH 分支刷新 lastSeen。这两个分支让"新建"与"重逢"可以走完全不同的业务逻辑,是同步类任务的主干模式。

三、锚定规则:MERGE 最锋利也最危险的地方

MERGE 括号里写的全部内容构成查找键。写多写少一个属性,语义天差地别:

// 锚定过窄:每次带着不同 age 来,都会新建节点 MERGE (p:Person {name: 'Alice', age: 30}) -- 来了个 age: 31 的 Alice? -- 查不到 → 又建一个
// 锚定过宽:只锚标签 MERGE (p:Person) -- 全库只有一个裸 Person 节点

正确姿势是用业务唯一键锚定节点,其余属性用 SET 补写

MERGE (p:Person {email: 'alice@example.com'}) // 邮箱是业务唯一键 ON CREATE SET p.name = 'Alice', p.age = 30 SET p.updated = datetime()

关系上的 MERGE 同理:两端点 + 关系类型(+ 有业务意义的关系属性)共同构成锚:

// 锚定"这条边"本身:同一对人的 KNOWS 边只建一次 MATCH (a:Person {email: 'alice@example.com'}), (b:Person {email: 'bob@example.com'}) MERGE (a)-[k:KNOWS]->(b) ON CREATE SET k.since = 2024

图:MERGE 的锚定决策路径

图:MERGE 的锚定决策路径

四、约束先行:让数据库替你把关

MERGE 的正确性依赖"锚定属性确实唯一",这件事不该靠自觉,交给唯一性约束:

// 唯一性约束:建约束会自动附带同名索引 CREATE CONSTRAINT person_email_unique IF NOT EXISTS FOR (p:Person) REQUIRE p.email IS UNIQUE
约束生效后: CREATE (p:Person {email: 'alice@example.com'}) -- 第二次插入 → ConstraintValidationFailed: 节点已存在,写入被拒绝

约束的完整清单(存在性、范围、类型等)随版本扩张,社区版唯一性约束最常用。铁律:先建约束,再上 MERGE——顺序反了,重复数据已经入库,还得先清洗。

五、变式:批量幂等写入

UNWIND 把列表摊成行,配合 MERGE 做批量幂等同步——这是第 4 章驱动编程的预告:

// 参数 $people 是 [{"email": "...", "name": "..."}, ...] UNWIND $people AS row MERGE (p:Person {email: row.email}) ON CREATE SET p.name = row.name, p.created = datetime() SET p.updated = datetime()
100 行输入 → 100 次幂等写入,1 个事务 重复执行 → 0 个新节点,100 次 lastSeen 刷新

💡 幂等是同步任务的生命线:消息队列的重投递、调度器的重跑、人工的误触发,全都打不乱一个幂等的 MERGE。

六、写入语句的评审清单

写入代码合并前的四个必查项,对应四类线上事故:

1. 锚定属性是否业务唯一键? —— 防重复节点 2. 是否先有约束再上线? —— 防脏数据入库 3. 批量写入是否 UNWIND 分批? —— 防事务超长 4. ON CREATE / ON MATCH 分支的逻辑是否都验证过? —— 防首次与再次执行行为不一致

第四条最常被漏测:本地库是空的,永远只走 ON CREATE;生产库里有存量数据,ON MATCH 分支一跑就暴露问题。用"跑两遍"作为写入语句的最小测试用例——第二遍必须零新增。

本节要点回顾

  • CREATE 无条件新建,只用于"确定是全新实体";生产默认 MERGE;
  • MERGE 的锚 = 括号里的全部内容:锚定业务唯一键,非锚属性用 SET 补;
  • ON CREATE / ON MATCH 分支区分"新建"与"重逢"两套逻辑;
  • 唯一性约束先于 MERGE 上线,让库替你把关;
  • UNWIND + MERGE 是批量幂等写入的标准形态。

写入要"对",还要"稳"。下一节看事务与 ACID 如何守住后者。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U