导航菜单

  • 1.langchain.intro
  • 2.langchain.chat_models
  • 3.langchain.prompts
  • 4.langchain.example_selectors
  • 5.output_parsers
  • 6.Runnable
  • 7.memory
  • 8.document_loaders
  • 9.text_splitters
  • 10.embeddings
  • 11.tool
  • 12.retrievers
  • 13.optimize
  • 14.项目介绍
  • 15.启动HTTP
  • 16.数据与模型
  • 17.权限管理
  • 18.知识库管理
  • 19.设置
  • 20.文档管理
  • 21.聊天
  • 22.API文档
  • 23.RAG优化
  • 24.索引时优化
  • 25.检索前优化
  • 26.检索后优化
  • 27.系统优化
  • 28.GraphRAG
  • 29.图
  • 30.为什么选择图数据库
  • 31.什么是 Neo4j
  • 32.安装和连接 Neo4j
  • 33.Neo4j核心概念
  • 34.Cypher基础
  • 35.模式匹配
  • 36.数据CRUD操作
  • 37.Python操作Neo4j
  • 38.GraphRAG
  • 39.查询和过滤
  • 40.结果处理和聚合
  • 41.语句组合
  • 42.子查询
  • 43.模式和约束
  • 44.日期时间处理
  • 45.Cypher内置函数
  • 46.py2neo
  • 47.Streamlit
  • 48.Pandas
  • 49.graphRAG
  • 50.deepdoc
  • 51.deepdoc
  • 52.deepdoc
  • 53.deepdoc
  • 54.deepdoc
  • Pillow
  • 1. 什么是CRUD操作
  • 2. 创建数据(CREATE)
    • 2.1 CREATE命令的基本语法
    • 2.2 创建节点
    • 2.3 创建带多个属性的节点
    • 2.4 创建关系
    • 2.5 创建复杂图结构
  • 3. 更新数据(SET)
    • 3.1 前置知识:SET命令
    • 3.2 更新节点属性
    • 3.3 更新多个属性
    • 3.4 使用表达式更新属性
    • 3.5 更新关系属性
    • 3.6 添加和移除标签
  • 4. 删除数据(DELETE/REMOVE)
    • 4.1 前置知识:DELETE和REMOVE的区别
    • 4.2 删除关系
    • 4.3 删除节点(DELETE)
    • 4.4 删除节点及其关系(DETACH DELETE)
    • 4.5 删除属性(REMOVE)
  • 5. 避免重复数据(MERGE)
    • 5.1 前置知识:为什么需要MERGE?
    • 5.2 MERGE节点
    • 5.3 MERGE关系
    • 5.4 ON CREATE SET 和 ON MATCH SET
    • 5.5 MERGE最佳实践
  • 6. 小结
    • 6.1 核心概念回顾
    • 6.2 CREATE vs MERGE 对比
    • 6.3 DELETE vs DETACH DELETE 对比
    • 6.4 最佳实践
    • 6.5 常见错误和解决方案

1. 什么是CRUD操作 #

在数据库操作中,CRUD是最基本的四个操作:

  • Create(创建):创建新的数据
  • Read(读取):查询和读取数据
  • Update(更新):修改现有数据
  • Delete(删除):删除数据

在图数据库中,CRUD操作有一些特殊之处:

  1. 创建:可以创建节点和关系,以及它们的属性
  2. 更新:可以更新节点和关系的属性,也可以添加或删除标签
  3. 删除:可以删除节点、关系或属性,但需要注意节点和关系之间的依赖关系

2. 创建数据(CREATE) #

创建数据是数据库操作的第一步。在Cypher中,使用CREATE关键字来创建节点和关系。

2.1 CREATE命令的基本语法 #

CREATE命令用于创建新的节点和关系。它的基本语法是:

  • 创建节点:CREATE (变量名:标签 {属性})
  • 创建关系:CREATE (节点1)-[:关系类型 {属性}]->(节点2)

2.2 创建节点 #

创建节点是最基本的操作。可以创建带标签和属性的节点。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建一个简单的演员节点
CREATE (a:Actor {name: "周星驰"})

// 查询创建的节点
MATCH (a:Actor)
RETURN a

// 创建电影节点
CREATE (m:Movie {title: "功夫"})

// 查询所有节点
MATCH (n)
RETURN n

2.3 创建带多个属性的节点 #

节点可以有多个属性,用于存储更多信息。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建带多个属性的演员节点
CREATE (a:Actor {
  name: "周星驰",
  born: 1962,
  birthplace: "香港",
  nickname: "星爷"
})

// 查询节点及其属性
MATCH (a:Actor)
RETURN a.name, a.born, a.birthplace, a.nickname

// 创建多个带属性的节点
CREATE (a1:Actor {name: "吴孟达", born: 1952, birthplace: "福建厦门"}),
       (a2:Actor {name: "朱茵", born: 1971, birthplace: "香港"})

// 查询所有演员
MATCH (a:Actor)
RETURN a.name, a.born, a.birthplace

2.4 创建关系 #

关系连接两个节点,也可以有自己的属性。

// 清空数据库
MATCH (n) DETACH DELETE n

// 先创建节点
CREATE (a1:Actor {name: "周星驰"}),
       (a2:Actor {name: "吴孟达"}),
       (m1:Movie {title: "功夫", released: 2004})

// 查询插入后的节点(还没有关系)
MATCH (n)
RETURN n

// 查询初始关系(应该为空)
MATCH (a:Actor)-[r]->(target)
RETURN count(r) AS initial_relationship_count

// 创建关系(无属性)- 合作关系
MATCH (a1:Actor {name: "周星驰"}),
      (a2:Actor {name: "吴孟达"})
CREATE (a1)-[:CO_STARRED_WITH]->(a2)

// 查询创建关系后的状态
MATCH (a:Actor)-[r]->(target)
RETURN a.name, type(r), target.name

// 创建带属性的出演关系
MATCH (a1:Actor {name: "周星驰"}),
      (m1:Movie {title: "功夫"})
CREATE (a1)-[:ACTED_IN {roles: ["阿星"], year: 2004}]->(m1)

// 查询所有节点和关系
MATCH (a:Actor)-[r]->(target)
RETURN a.name, type(r), target.title, r

// 查询出演关系及其属性
MATCH (a:Actor)-[r:ACTED_IN]->(m:Movie)
RETURN a.name, r.roles, r.year, m.title

2.5 创建复杂图结构 #

可以一次性创建多个节点和关系,构建复杂的图结构。

// 清空数据库
MATCH (n) DETACH DELETE n

// 一次性创建多个节点和关系(周星驰电影宇宙)
CREATE (zxc:Actor {name: "周星驰", born: 1962}),
       (wmd:Actor {name: "吴孟达", born: 1952}),
       (zy:Actor {name: "朱茵", born: 1971}),
       (m1:Movie {title: "大话西游", released: 1995}),
       (m2:Movie {title: "喜剧之王", released: 1999}),
       (zxc)-[:CO_STARRED_WITH]->(wmd),
       (zxc)-[:CO_STARRED_WITH]->(zy),
       (zxc)-[:ACTED_IN {roles: ["至尊宝"]}]->(m1),
       (zy)-[:ACTED_IN {roles: ["紫霞仙子"]}]->(m1),
       (zxc)-[:ACTED_IN {roles: ["尹天仇"]}]->(m2)

// 查询完整的图结构
MATCH (a:Actor)-[r]->(target)
RETURN a.name, type(r), COALESCE(target.name, target.title) AS target

// 查询演员合作关系网络
MATCH (a1:Actor)-[:CO_STARRED_WITH]->(a2:Actor)
RETURN a1.name, a2.name

// 查询出演关系
MATCH (a:Actor)-[r:ACTED_IN]->(m:Movie)
RETURN a.name, m.title, r.roles

3. 更新数据(SET) #

更新数据是修改现有节点或关系属性的操作。在Cypher中,使用SET关键字来更新属性。

3.1 前置知识:SET命令 #

SET命令用于设置或更新节点和关系的属性。它的基本语法是:

  • 更新节点属性:SET 节点变量.属性名 = 值
  • 更新关系属性:SET 关系变量.属性名 = 值

3.2 更新节点属性 #

可以更新节点的单个或多个属性。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建测试数据
CREATE (a:Actor {name: "周星驰", born: 1962})

// 查询插入后的初始数据
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, a.born

// 更新单个属性
MATCH (a:Actor {name: "周星驰"})
SET a.nickname = "星爷"
RETURN a

// 查询更新后的节点
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, a.born, a.nickname

// 更新另一个属性
MATCH (a:Actor {name: "周星驰"})
SET a.birthplace = "香港"
RETURN a.name, a.born, a.birthplace

// 查询最终状态
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, a.born, a.nickname, a.birthplace

3.3 更新多个属性 #

可以一次更新多个属性,用逗号分隔。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建测试数据
CREATE (a:Actor {name: "周星驰", born: 1962})

// 查询插入后的初始数据
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, a.born

// 一次更新多个属性
MATCH (a:Actor {name: "周星驰"})
SET a.nickname = "星爷", a.birthplace = "香港", a.profession = "演员/导演"
RETURN a

// 查询更新后的所有属性
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, a.born, a.nickname, a.birthplace, a.profession

// 创建更多测试数据
CREATE (a2:Actor {name: "吴孟达", born: 1952})

// 更新多个节点的属性
MATCH (a:Actor)
SET a.updated = true, a.update_time = timestamp()
RETURN a.name, a.updated, a.update_time

3.4 使用表达式更新属性 #

可以使用表达式来计算新的属性值。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建测试数据(电影节点)
CREATE (m:Movie {title: "功夫", released: 2004, budget: 20000000})

// 查询插入后的初始数据
MATCH (m:Movie {title: "功夫"})
RETURN m.title, m.released, m.budget

// 使用表达式更新属性(计算距今年数)
MATCH (m:Movie {title: "功夫"})
SET m.years_ago = 2024 - m.released
RETURN m.title, m.years_ago

// 查询更新后的年数
MATCH (m:Movie {title: "功夫"})
RETURN m.title, m.released, m.years_ago

// 使用表达式计算预算(美元转人民币,假设汇率7)
MATCH (m:Movie {title: "功夫"})
SET m.budget_cny = m.budget * 7
RETURN m.title, m.budget, m.budget_cny

// 使用字符串拼接
MATCH (m:Movie {title: "功夫"})
SET m.display_name = m.title + " (" + toString(m.released) + ")"
RETURN m.display_name

// 使用条件表达式判断电影时代
MATCH (m:Movie {title: "功夫"})
SET m.era = CASE 
  WHEN m.released < 1990 THEN "80年代"
  WHEN m.released < 2000 THEN "90年代"
  WHEN m.released < 2010 THEN "00年代"
  ELSE "10年代后"
END
RETURN m.title, m.released, m.era

// 查询最终状态
MATCH (m:Movie {title: "功夫"})
RETURN m.title, m.released, m.budget, m.budget_cny, m.display_name, m.era

3.5 更新关系属性 #

关系的属性也可以使用SET来更新。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建测试数据
CREATE (a:Actor {name: "周星驰"}),
       (m:Movie {title: "少林足球", released: 2001}),
       (a)-[:ACTED_IN {roles: ["五师兄"], year: 2001}]->(m)

// 查询插入后的初始关系数据
MATCH (a:Actor {name: "周星驰"})-[r:ACTED_IN]->(m:Movie)
RETURN a.name, r.roles, r.year, m.title

// 更新关系属性
MATCH (a:Actor {name: "周星驰"})-[r:ACTED_IN]->(m:Movie)
SET r.award = "最佳导演"
RETURN a.name, r.roles, r.year, r.award, m.title

// 查询更新后的关系
MATCH (a:Actor {name: "周星驰"})-[r:ACTED_IN]->(m:Movie)
RETURN a.name, r.roles, r.year, r.award, m.title

// 更新关系的多个属性
MATCH (a:Actor {name: "周星驰"})-[r:ACTED_IN]->(m:Movie)
SET r.roles = ["五师兄/星"], r.is_lead = true, r.box_office = 60000000
RETURN a.name, r.roles, r.is_lead, r.box_office, m.title

// 使用表达式更新关系属性
MATCH (a:Actor)-[r:ACTED_IN]->(m:Movie)
SET r.years_ago = 2024 - r.year
RETURN a.name, r.year, r.years_ago, m.title

// 查询最终状态
MATCH (a:Actor)-[r:ACTED_IN]->(m:Movie)
RETURN a.name, r.roles, r.year, r.award, r.box_office, r.years_ago, m.title

3.6 添加和移除标签 #

标签是节点的分类标识,可以使用SET添加标签,使用REMOVE移除标签。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建测试数据
CREATE (a:Actor {name: "周星驰", born: 1962})

// 查询插入后的初始标签
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, labels(a)

// 添加标签(周星驰也是导演)
MATCH (a:Actor {name: "周星驰"})
SET a:Director
RETURN labels(a), a

// 查询添加标签后的状态
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, labels(a)

// 添加多个标签(周星驰还是编剧和制片人)
MATCH (a:Actor {name: "周星驰"})
SET a:Writer:Producer
RETURN labels(a), a

// 查询节点的所有标签
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, labels(a)

// 移除标签
MATCH (a:Actor {name: "周星驰"})
REMOVE a:Producer
RETURN labels(a), a

// 查询移除标签后的状态
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, labels(a)

// 移除多个标签
MATCH (a:Actor {name: "周星驰"})
REMOVE a:Writer
RETURN labels(a), a

// 查看最终标签(应该是 Actor 和 Director)
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, labels(a)

4. 删除数据(DELETE/REMOVE) #

删除数据是移除节点、关系或属性的操作。在Cypher中,使用DELETE删除节点和关系,使用REMOVE删除属性。

4.1 前置知识:DELETE和REMOVE的区别 #

  • DELETE:用于删除节点和关系
  • REMOVE:用于删除属性和标签

4.2 删除关系 #

删除关系时,只删除关系本身,不删除关系两端的节点。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建测试数据
CREATE (a1:Actor {name: "周星驰"}),
       (a2:Actor {name: "吴孟达"}),
       (m1:Movie {title: "功夫", released: 2004}),
       (a1)-[:CO_STARRED_WITH]->(a2),
       (a1)-[:ACTED_IN]->(m1)

// 查询删除前的关系
MATCH (a:Actor)-[r]->(target)
RETURN a.name, type(r), COALESCE(target.name, target.title) AS target

// 删除特定关系(合作关系)
MATCH (a1:Actor {name: "周星驰"})-[r:CO_STARRED_WITH]->(a2:Actor)
DELETE r

// 查询删除后的关系(合作关系已删除,出演关系还在)
MATCH (a:Actor)-[r]->(target)
RETURN a.name, type(r), COALESCE(target.name, target.title) AS target

// 删除所有出演关系
MATCH ()-[r:ACTED_IN]->()
DELETE r

// 确认节点仍然存在
MATCH (n)
RETURN n

4.3 删除节点(DELETE) #

使用DELETE删除节点时,只能删除没有关系的节点。如果节点有关系,必须先删除关系。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建测试数据
CREATE (a1:Actor {name: "周星驰"}),
       (a2:Actor {name: "吴孟达"}),
       (a3:Actor {name: "朱茵"}),
       (a1)-[:CO_STARRED_WITH]->(a2)

// 查询插入后的初始数据
MATCH (n)
RETURN n

// 查询节点和关系
MATCH (a:Actor)-[r]->(target)
RETURN a.name, type(r), target.name

// 删除没有关系的节点(可以成功)
MATCH (a:Actor {name: "朱茵"})
DELETE a

// 查询剩余节点
MATCH (n)
RETURN n

// 尝试删除有关系的节点(会失败)
// MATCH (a:Actor {name: "周星驰"})
// DELETE a
// 错误:Cannot delete node<id>, because it still has relationships.

// 先删除关系,再删除节点
MATCH (a1:Actor {name: "周星驰"})-[r:CO_STARRED_WITH]->(a2:Actor)
DELETE r

// 查询删除关系后的状态
MATCH (n)
RETURN n

MATCH (a:Actor {name: "周星驰"})
DELETE a

// 查询最终结果
MATCH (n)
RETURN n

4.4 删除节点及其关系(DETACH DELETE) #

如果要删除一个节点及其所有关系,应该使用DETACH DELETE。这是删除节点的推荐方式。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建测试数据
CREATE (a1:Actor {name: "周星驰"}),
       (a2:Actor {name: "吴孟达"}),
       (a3:Actor {name: "朱茵"}),
       (m1:Movie {title: "大话西游", released: 1995}),
       (a1)-[:CO_STARRED_WITH]->(a2),
       (a1)-[:CO_STARRED_WITH]->(a3),
       (a1)-[:ACTED_IN]->(m1)

// 查询删除前的图结构
MATCH (a:Actor)-[r]->(target)
RETURN a.name, type(r), COALESCE(target.name, target.title) AS target

// 使用 DETACH DELETE 删除节点及其所有关系
MATCH (a:Actor {name: "周星驰"})
DETACH DELETE a

// 查询删除后的结果(周星驰及其所有关系都被删除)
MATCH (n)
RETURN n

// 删除所有节点及其关系
MATCH (n)
DETACH DELETE n

// 确认数据库已清空
MATCH (n)
RETURN count(n) AS node_count

4.5 删除属性(REMOVE) #

可以使用REMOVE删除节点或关系的属性。

// 清空数据库
MATCH (n) DETACH DELETE n

// 创建测试数据
CREATE (a:Actor {name: "周星驰", born: 1962, birthplace: "香港", nickname: "星爷"}),
       (m:Movie {title: "功夫", released: 2004}),
       (a)-[:ACTED_IN {roles: ["阿星"], year: 2004, award: "最佳导演"}]->(m)

// 查询插入后的初始节点属性
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, a.born, a.birthplace, a.nickname

// 查询插入后的初始关系属性
MATCH (a:Actor {name: "周星驰"})-[r:ACTED_IN]->(m:Movie)
RETURN a.name, r.roles, r.year, r.award, m.title

// 删除节点的单个属性
MATCH (a:Actor {name: "周星驰"})
REMOVE a.nickname
RETURN a

// 查询删除后的属性
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, a.born, a.birthplace, a.nickname

// 删除节点的多个属性
MATCH (a:Actor {name: "周星驰"})
REMOVE a.birthplace, a.born
RETURN a

// 查询删除多个属性后的状态
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, a.born, a.birthplace, a.nickname

// 删除关系属性
MATCH (a:Actor {name: "周星驰"})-[r:ACTED_IN]->(m:Movie)
REMOVE r.award
RETURN a.name, r.roles, r.year, r.award, m.title

// 查询删除关系属性后的状态
MATCH (a:Actor {name: "周星驰"})-[r:ACTED_IN]->(m:Movie)
RETURN a.name, r.roles, r.year, r.award, m.title

// 删除关系的多个属性
MATCH (a:Actor {name: "周星驰"})-[r:ACTED_IN]->(m:Movie)
REMOVE r.roles, r.year
RETURN a.name, r, m.title

// 查询最终状态
MATCH (a:Actor {name: "周星驰"})-[r:ACTED_IN]->(m:Movie)
RETURN a.name, r, m.title

5. 避免重复数据(MERGE) #

MERGE是Cypher中非常重要的命令,它确保数据存在(不存在时创建),避免重复数据。

5.1 前置知识:为什么需要MERGE? #

在使用CREATE创建数据时,如果多次执行相同的CREATE语句,会创建重复的节点。MERGE可以解决这个问题:

  • 如果数据不存在:创建新数据
  • 如果数据已存在:匹配现有数据(不创建重复数据)

5.2 MERGE节点 #

使用MERGE可以确保节点只创建一次。

// 清空数据库
MATCH (n) DETACH DELETE n

// 查询初始状态(应该为空)
MATCH (a:Actor)
RETURN count(a) AS initial_count

// 第一次执行 MERGE:节点不存在,会创建
MERGE (a:Actor {name: "周星驰", born: 1962})
RETURN a

// 查询第一次 MERGE 后的节点
MATCH (a:Actor)
RETURN a.name, a.born, count(a) AS count

// 第二次执行相同的 MERGE:节点已存在,不会创建重复节点
MERGE (a:Actor {name: "周星驰", born: 1962})
RETURN a

// 查询节点(只有一个节点,证明没有重复创建)
MATCH (a:Actor)
RETURN a.name, a.born, count(a) AS count

// 对比:使用 CREATE 会创建重复节点
CREATE (a:Actor {name: "吴孟达", born: 1952})
CREATE (a:Actor {name: "吴孟达", born: 1952})

// 查询(会有两个重复的节点)
MATCH (a:Actor {name: "吴孟达"})
RETURN a.name, a.born, count(a) AS count

// 使用 MERGE 避免重复
MERGE (a:Actor {name: "朱茵", born: 1971})
MERGE (a:Actor {name: "朱茵", born: 1971})

// 查询(只有一个节点)
MATCH (a:Actor {name: "朱茵"})
RETURN a.name, a.born, count(a) AS count

// 查询所有节点
MATCH (a:Actor)
RETURN a.name, a.born

5.3 MERGE关系 #

也可以使用MERGE来确保关系只创建一次。

// 清空数据库
MATCH (n) DETACH DELETE n

// 先创建节点
CREATE (a1:Actor {name: "周星驰"}),
       (a2:Actor {name: "吴孟达"}),
       (m1:Movie {title: "功夫", released: 2004})

// 查询插入后的初始节点
MATCH (n)
RETURN n

// 查询初始关系(应该为空)
MATCH (a1:Actor {name: "周星驰"})-[r:CO_STARRED_WITH]->(a2:Actor {name: "吴孟达"})
RETURN count(r) AS initial_relationship_count

// 使用 MERGE 创建关系(第一次)
MATCH (a1:Actor {name: "周星驰"}),
      (a2:Actor {name: "吴孟达"})
MERGE (a1)-[:CO_STARRED_WITH]->(a2)
RETURN a1.name, a2.name

// 查询第一次 MERGE 后的关系
MATCH (a1:Actor {name: "周星驰"})-[r:CO_STARRED_WITH]->(a2:Actor {name: "吴孟达"})
RETURN count(r) AS relationship_count

// 再次执行相同的 MERGE(不会创建重复关系)
MATCH (a1:Actor {name: "周星驰"}),
      (a2:Actor {name: "吴孟达"})
MERGE (a1)-[:CO_STARRED_WITH]->(a2)
RETURN a1.name, a2.name

// 查询关系(只有一条,证明没有重复创建)
MATCH (a1:Actor {name: "周星驰"})-[r:CO_STARRED_WITH]->(a2:Actor {name: "吴孟达"})
RETURN count(r) AS relationship_count

// MERGE 节点和关系一起
MERGE (a:Actor {name: "朱茵", born: 1971})
MERGE (m:Movie {title: "大话西游", released: 1995})
MERGE (a)-[:ACTED_IN]->(m)
RETURN a.name, m.title

// 查询 MERGE 后的节点和关系
MATCH (a:Actor {name: "朱茵"})-[r:ACTED_IN]->(m:Movie {title: "大话西游"})
RETURN a.name, m.title, count(r) AS relationship_count

// 再次执行(不会创建重复)
MERGE (a:Actor {name: "朱茵", born: 1971})
MERGE (m:Movie {title: "大话西游", released: 1995})
MERGE (a)-[:ACTED_IN]->(m)
RETURN a.name, m.title

// 查询最终状态(关系数量应该不变)
MATCH (a:Actor {name: "朱茵"})-[r:ACTED_IN]->(m:Movie {title: "大话西游"})
RETURN a.name, m.title, count(r) AS relationship_count

5.4 ON CREATE SET 和 ON MATCH SET #

可以在MERGE时使用ON CREATE SET和ON MATCH SET来分别处理创建和匹配的情况。

// 清空数据库
MATCH (n) DETACH DELETE n

// 查询初始状态(应该为空)
MATCH (m:Movie {title: "功夫"})
RETURN count(m) AS initial_count

// 第一次 MERGE:节点不存在,执行 ON CREATE SET
MERGE (m:Movie {title: "功夫"})
ON CREATE SET m.released = 2004, m.created_at = timestamp(), m.view_count = 1
ON MATCH SET m.view_count = m.view_count + 1, m.last_viewed = timestamp()
RETURN m

// 查询第一次 MERGE 后的节点(应该执行了 ON CREATE SET)
MATCH (m:Movie {title: "功夫"})
RETURN m.title, m.released, m.view_count, m.created_at, m.last_viewed

// 第二次 MERGE:节点已存在,执行 ON MATCH SET
MERGE (m:Movie {title: "功夫"})
ON CREATE SET m.released = 2004, m.created_at = timestamp(), m.view_count = 1
ON MATCH SET m.view_count = m.view_count + 1, m.last_viewed = timestamp()
RETURN m

// 查询节点(view_count 应该增加了)
MATCH (m:Movie {title: "功夫"})
RETURN m.title, m.released, m.view_count, m.created_at, m.last_viewed

// 再次执行 MERGE
MERGE (m:Movie {title: "功夫"})
ON CREATE SET m.released = 2004, m.created_at = timestamp(), m.view_count = 1
ON MATCH SET m.view_count = m.view_count + 1, m.last_viewed = timestamp()
RETURN m.view_count

// 查看最终结果
MATCH (m:Movie {title: "功夫"})
RETURN m.title, m.view_count, m.created_at, m.last_viewed

5.5 MERGE最佳实践 #

使用MERGE时,应该使用唯一标识符(如ID、特定属性组合等)作为匹配条件。

// 清空数据库
MATCH (n) DETACH DELETE n

// 查询初始状态
MATCH (n)
RETURN count(n) AS initial_count

// 最佳实践:使用唯一标识符(title + released)作为匹配条件
MERGE (m:Movie {title: "少林足球", released: 2001})
ON CREATE SET m.director = "周星驰", m.created_at = timestamp()
ON MATCH SET m.last_updated = timestamp()
RETURN m

// 查询 MERGE 后的节点
MATCH (m:Movie {title: "少林足球"})
RETURN m.title, m.released, m.director, m.created_at, m.last_updated

// 最佳实践:使用 ID 作为唯一标识符
MERGE (a:Actor {id: "ACTOR001"})
ON CREATE SET a.name = "周星驰", a.born = 1962, a.created_at = timestamp()
RETURN a

// 查询 MERGE 后的演员
MATCH (a:Actor {id: "ACTOR001"})
RETURN a.name, a.id, a.born, a.created_at

// ❌ 不推荐:使用非唯一属性(name)作为匹配条件,可能创建重复节点
MERGE (a:Actor {name: "周星驰"})
RETURN a

// 查询使用 name 匹配的节点
MATCH (a:Actor {name: "周星驰"})
RETURN a.name, a.born, count(a) AS count

// 推荐:组合唯一属性
MERGE (a:Actor {name: "周星驰", born: 1962})
ON CREATE SET a.nickname = "星爷"
RETURN a

// 查询组合唯一属性的节点
MATCH (a:Actor {name: "周星驰", born: 1962})
RETURN a.name, a.born, a.nickname

// 最佳实践:MERGE 节点和关系时,确保节点已存在或使用 MERGE
MERGE (a:Actor {name: "吴孟达", born: 1952})
ON CREATE SET a.nickname = "达叔"
MERGE (m:Movie {title: "少林足球", released: 2001})
ON CREATE SET m.director = "周星驰"
MERGE (a)-[:ACTED_IN {roles: ["黄金右脚"]}]->(m)
RETURN a.name, m.title

// 查询结果
MATCH (a:Actor)-[r:ACTED_IN]->(m:Movie)
RETURN a.name, m.title, r.roles

// 查询最终状态
MATCH (n)
RETURN labels(n), count(n) AS count

6. 小结 #

6.1 核心概念回顾 #

介绍了Cypher中数据创建、更新和删除的核心操作:

操作类型 命令 说明 示例
创建节点 CREATE (n:Label {property: value}) 创建新节点 CREATE (a:Actor {name: '周星驰'})
创建关系 CREATE (a)-[:REL]->(b) 创建新关系 CREATE (a)-[:ACTED_IN]->(m)
更新属性 SET n.property = value 更新节点或关系的属性 SET m.released = 2004
删除关系 DELETE r 删除关系 DELETE r
删除节点 DELETE n 或 DETACH DELETE n 删除节点 DETACH DELETE n
删除属性 REMOVE n.property 删除属性 REMOVE a.nickname
避免重复 MERGE (n:Label {id: value}) 存在则匹配,不存在则创建 MERGE (m:Movie {title: '功夫'})

6.2 CREATE vs MERGE 对比 #

特性 CREATE MERGE
行为 总是创建新数据 存在则匹配,不存在则创建
重复数据 可能创建重复数据 避免重复数据
使用场景 确定要创建新数据时 避免重复数据时
性能 较快 较慢(需要检查是否存在)

6.3 DELETE vs DETACH DELETE 对比 #

特性 DELETE DETACH DELETE
删除节点 只能删除无关系的节点 删除节点及其所有关系
删除关系 可以删除关系 不单独删除关系
安全性 如果节点有关系会失败 总是成功
使用场景 确定节点没有关系时 删除节点及其所有关系时(推荐)

6.4 最佳实践 #

  1. 创建数据

    • 使用CREATE创建确定要新建的数据
    • 使用MERGE避免重复数据
    • 在MERGE中使用唯一标识符(如email、ID)
  2. 更新数据

    • 使用SET更新属性
    • 可以一次更新多个属性
    • 使用表达式计算新值
  3. 删除数据

    • 使用DETACH DELETE删除节点(更安全)
    • 删除前先查询确认
    • 使用REMOVE删除属性
  4. 避免重复

    • 使用MERGE避免重复创建
    • 在MERGE中使用唯一标识符
    • 使用ON CREATE和ON MATCH处理不同情况

6.5 常见错误和解决方案 #

错误 原因 解决方案
无法删除有关系的节点 节点仍有关联关系 使用DETACH DELETE
MERGE创建了重复节点 匹配条件不唯一 使用唯一标识符(如email、ID)
更新属性失败 节点不存在 先使用MATCH确认节点存在,或使用MERGE
CREATE创建了重复数据 多次执行相同的CREATE 使用MERGE代替CREATE
← 上一节 35.模式匹配 下一节 37.Python操作Neo4j →

访问验证

请输入访问令牌

Token不正确,请重新输入