Files
2026-05-12 09:41:56 +08:00

487 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Neo4J 简单应用
## 一、什么是知识图谱
**知识图谱(Knowledge Graph, KG** 源于自然语言理解,其目标是用一种结构化的方式,来描述现实世界中的实体及其相互关系。它主要由两个核心要素构成:
1. **节点(Nodes**:代表现实世界中的“实体”(Entities),例如一个人、一部电影、一家公司或一个具体概念。
2. **边(Edges**:代表实体与实体之间的“关系”(Relations)。
这些元素共同构成了一个庞大的语义网络,其基本结构可以表示为 **(实体)- [关系] -> (实体)** 的三元组(Triples)。例如,“饺子”和“哪吒2”是两个实体,“导演”就是它们之间的关系,构成一个知识三元组:(饺子)- [导演] -> (哪吒2)。
## 二、知识图谱的应用
知识图谱并非一个孤立的学术概念,它在工业界有着广泛且深入的应用,尤其是在需要深度结合领域知识的场景中。
### 2.1 风险识别与网络分析
俗话说“近朱者赤,近墨者黑”,在许多领域,一个实体的风险或属性,往往与其关联的其他实体有很强的相关性。知识图谱正是挖掘这种关联性的利器。
- **犯罪网络侦查**:公安部门可以利用通话记录、社交关系、转账流水等信息构建犯罪嫌疑人网络。在这个网络中,如果某个节点与多个已知的犯罪分子有直接或间接的联系,那么他参与犯罪的可能性就大大增加。通过分析网络中的核心人物(连接数最多的节点)和资金流向,可以有效地打击整个犯罪团伙。
- **信用卡反欺诈**:银行可以将申请人的信息(如电话、地址、公司)构建成一个庞大的关系网络。通过分析这张网络,可以识别出“欺诈团伙”——例如,多个申请人共享同一个联系电话或家庭住址,或者与已知的欺诈分子有紧密的社交关系。
### 2.2 智能诊断与运维
- **工业设备运维**:将设备的各种“故障现象”、“故障原因”、“解决方案”和“所需零件”构建成知识图谱。当设备出现问题时,系统可以根据上报的现象,在图谱中进行推理,快速定位可能的原因,并给出维修建议,甚至可以提示维修人员需要携带哪些工具和备件,从而提高维修效率。
- **医疗辅助诊断**:医疗领域知识繁杂,可以通过构建“病症”、“疾病”、“检查项目”、“治疗方案”、“药品”之间的关系图谱。医生输入患者的症状后,系统可以辅助推荐需要进行的检查,并根据检查结果在图谱中推理,给出可能的诊断建议和治疗方案,帮助实现规范化诊疗。
### 2.3 特定领域聊天机器人
对于通用领域的开放式聊天,大语言模型(LLM)已展现出强大的能力。但在许多垂直领域,基于知识图谱的问答系统(KBQA)因其答案的准确性和可解释性,仍然具有不可替代的价值。其工作流程通常如下:
1. **意图识别**:首先判断用户提问的意图。例如,“我想买一张明天上午的故宫门票”这个问题的意图是“票务预订”。
2. **槽位填充 (实体抽取)**:从问题中抽取出关键信息,即“实体”。例如:`景点: 故宫`, `时间: 明天上午`, `数量: 一张`
3. **知识查询**:利用抽取出的实体,在知识图谱(或数据库)中进行精确查询。
4. **回复生成**:将查询到的结果,通过预设的模板生成自然语言回复。
这种方式虽然不如 LLM 灵活,但在机票预订、酒店查询、银行客服等业务逻辑明确的场景中,能够提供更加可靠和可控的服务。
## 三、知识图谱的构建
如何从海量的、非结构化的文本(如新闻、财报、医疗记录)中,自动地构建出结构化的知识图谱,是整个技术流程的核心挑战。
### 3.1 经典构建流程
传统的知识图谱构建过程主要依赖于两项关键的 NLP 技术:
1. **命名实体识别 (Named Entity Recognition, NER)**:从文本中识别并抽取出特定类别的实体。例如,在“英伟达发布了专为 AI 设计的 Blackwell 芯片”这句话中,识别出“英伟达”(公司)、“Blackwell”(产品)。这些被抽取的实体将成为知识图谱中的 **节点**
2. **关系抽取 (Relation Extraction, RE)**:在识别出实体的基础上,进一步判断实体与实体之间存在何种语义关系。在上面的例子中,模型需要判断“英伟达”和“Blackwell”之间的关系是“发布”。这个关系将成为连接两个节点的 **边**
通过对大量文本进行这两步处理,我们就能源源不断地抽取出知识三元组,最终汇聚成一个庞大的知识图谱。
### 3.2 大模型带来的革新
随着大语言模型的兴起,传统的 NLP 任务流程正在被重塑。LLM 同样具备强大的实体识别和关系抽取能力,但这并不意味着对传统流程的简单替代,而是呈现出深度融合的趋势。
- **局限性与挑战**:完全依赖 LLM 会面临成本高昂、数据隐私(使用闭源 API 时)、以及“幻觉”问题,即模型可能会编造事实。
- **融合方案**:为了结合知识图谱的准确性和大模型的推理能力,微软提出了 GraphRAG。原理是将知识图谱作为一个可靠、可随时更新的 **外部知识库**,并基于图结构进行“子图检索”(如社区发现、路径搜索等),而非检索孤立事实。当用户提问时:
1. 利用模型从问题中识别出核心实体与约束。
2. 在图中检索与之高度相关的子图(社区/路径/邻域),获得准确且可解释的事实与关系。
3. 将该子图的结构化信息作为上下文,连同原始问题一起输入给大语言模型,生成基于证据的答案。
## 四、图数据库:Neo4j
> [Neo4j 官方文档](https://neo4j.com/docs/)
知识图谱需要专门的数据库进行存储和查询,这类数据库被称为 **图数据库 (Graph Database)**。其中,与传统的关系型数据库(如 MySQL)相比,图数据库的优势在于其对“关系”的查询性能。对于需要进行多层关系遍历的复杂查询(例如,查询“我朋友的朋友”),图数据库的效果远超关系型数据库。而 **Neo4j** 就是目前比较流行的一款开源图数据库。
### 4.1 核心概念
Neo4j 的数据模型主要包含以下几个概念:
- **节点 (Node)**:节点是图中的基本数据单元,用于表示现实世界中的实体,例如一个人、一家公司、一本书或一个账户。在关系型数据库中,节点可以类比为表中的一行。
- **标签 (Label)**:用于为节点分类或打上“类型”标记。一个节点可以拥有一个或多个标签。例如,一个节点可以同时拥有 `:Person``:Author` 两个标签,表示这个人既是一个普通人,也是一位作者。
- **关系 (Relationship)**:这是图数据库的精髓所在,它以一种富有表现力的方式连接两个节点,并明确地定义了它们之间的联系。每个关系都具有以下特点:
- **有方向**:关系总是从一个“起始节点”指向一个“结束节点”。
- **有类型**:每个关系都必须有一个类型(例如 `:FRIENDS_WITH`, `:PURCHASED`),用来描述连接的性质。
- **可以拥有属性**:和节点一样,关系也可以存储属性,例如,一个 `:PURCHASED` 关系可以有一个 `date` 属性来记录购买日期。
- **属性 (Property)**:属性是以键值对(Key-Value)形式存储在节点和关系上的详细信息。键是字符串,值可以是各种基本数据类型(如字符串、数字、布尔值)或它们的数组。
这四个概念共同构成了一个灵活而强大的数据模型。
```mermaid
graph LR
A["Alice:Person {name: 'Alice'}"]
B["Bob:Person {name: 'Bob'}"]
A -- "KNOWS {since: 2020}" --> B
```
> 在上图中,`Alice` 和 `Bob` 是 **节点**`:Person` 是 **标签**`{name: 'Alice'}` 是 **属性**`KNOWS` 则是连接它们的 **关系** 类型,而 `{since: 2020}` 是这段关系上的 **属性**。
### 4.2 查询语言:Cypher
Cypher 是 Neo4j 的声明式图形查询语言,它的语法灵感来源于 SQL,但针对图的特性进行了优化。通过 Cypher,我们可以用一种直观且高效的方式来查询和操作图数据。
例如,要查找在电影《黑客帝国》(The Matrix) 中出演过的所有演员,可以使用以下查询:
```cypher
MATCH (actor:Person)-[:ACTED_IN]->(movie:Movie {title: 'The Matrix'})
RETURN actor.name
```
官方的 Cypher 语法速查表([在线版本](https://neo4j.com/docs/cypher-refcard/4.4/))汇总了常用的命令、操作符和语法结构,可供读者快速查阅。
<div align="center">
<img src="images/1_4_2_1.png" alt="Cypher 语法速查表" width="100%" />
<p>图 1.1: Cypher 语法速查表 (Cypher Refcard)</p>
</div>
### 4.3 安装与使用
对于初学者和开发者,推荐以下两种主流的安装方式。
1. **Neo4j Desktop (推荐用于本地学习)**
- **安装**:
1. 访问 [Neo4j 官网](https://neo4j.com/download/),在 “Neo4j for Desktop” 板块点击 “Download” 按钮。
<div align="center">
<img src="images/1_4_3_1.png" alt="Neo4j Desktop 下载页面" width="100%" />
<p>图 1.2: 在官网点击下载</p>
</div>
2. 页面会跳转至一个注册表单。可以填写任意信息,然后点击 “Download Desktop” 按钮,浏览器将自动开始下载安装包。
<div align="center">
<img src="images/1_4_3_2.png" alt="下载前填写表单" width="100%" />
<p>图 1.3: 填写注册表单</p>
</div>
3. 下载完成后,双击安装文件,程序会自动进行安装。
4. 安装完成后首次启动,会看到许可协议界面,点击 “Continue” 即可完成最后的设置。
<div align="center">
<img src="images/1_4_3_3.png" alt="同意许可协议" width="100%" />
<p>图 1.4: 首次启动并同意许可协议</p>
</div>
2. **Docker (推荐用于服务器部署与跨平台开发)**
- **安装**: 只需一行命令即可完成拉取镜像和启动容器。
```bash
docker run \
--name my-neo4j \
-p 7474:7474 -p 7687:7687 \
-d \
-v $HOME/neo4j/data:/data \
-v $HOME/neo4j/logs:/logs \
--env NEO4J_AUTH=neo4j/password \
neo4j:latest
```
- **参数说明**:
- `-p 7474:7474`: 将容器的 HTTP 端口映射到本机,用于浏览器访问。
- `-p 7687:7687`: 将容器的 Bolt 驱动端口映射到本机,用于代码连接。
- `-v $HOME/neo4j/data:/data`: 将数据目录挂载到本机,确保数据持久化。
- `--env NEO4J_AUTH=neo4j/password`: 设置数据库的初始用户名和密码(此处为 `neo4j/password`)。
- `neo4j:latest`: 使用最新的官方镜像。
安装好 Neo4j 后。我们就可以学习一些 Neo4j 的基本用法了。
## 五、创建并连接数据库
在使用 Neo4j 进行开发时,首先需要在 Neo4j Desktop 中创建一个本地数据库实例(Instance)。这个过程非常直观。
1. **创建实例**:打开 Neo4j Desktop,在 “Local instances” 页面点击 “Create instance” 按钮。
<div align="center">
<img src="images/2_1_1.png" alt="创建实例" width="100%" />
<p>图 2.1: 点击创建实例</p>
</div>
2. **配置实例**:在弹出的窗口中,为实例命名(例如 `base nlp`),选择所需的 Neo4j 版本,并为默认用户 `neo4j` 设置一个能记住的密码。完成后点击 “Create”。
<div align="center">
<img src="images/2_1_2.png" alt="配置实例" width="100%" />
<p>图 2.2: 配置实例信息</p>
</div>
3. **启动与连接**:实例创建后会自动启动,状态显示为 “RUNNING”。此时,可以通过浏览器直接访问 `http://127.0.0.1:7474` 来打开 Neo4j Browser。
<div align="center">
<img src="images/2_1_3.png" alt="启动实例" width="100%" />
<p>图 2.3: 实例创建成功并运行</p>
</div>
在浏览器打开的连接界面中,使用刚刚设置的密码进行连接。
<div align="center">
<img src="images/2_1_4.png" alt="连接实例" width="100%" />
<p>图 2.4: 使用密码连接数据库</p>
</div>
## 六、增删查改
数据库操作的核心无外乎增删查改(CRUD),下面来使用 Cypher,围绕一个菜品信息图谱的场景,逐一介绍这些基本操作。
### 6.1 场景设定
为了方便演示,先设定好本次实践所需要用到的实体、属性和关系。
- **实体/标签 (Labels)**:
- `Ingredient`: 食材,拥有 `name`, `category`(类别), `origin`(产地), `tags`(标签,数组)等属性。
- `Dish`: 菜品,拥有 `name`, `cuisine`(菜系)等属性。
- **关系 (Relationships)**:
- `(Dish)-[:包含]->(Ingredient)`: 表示某菜品包含某种食材,关系上可以有 `用量` 属性。
- `(Dish)-[:主要食材]->(Ingredient)`: 表示某菜品的主要食材是某种食材。
- `(Dish)-[:调味]->(Ingredient)`: 表示某菜品使用某种食材进行调味。
### 6.2 创建 (CREATE)
`CREATE` 语句用于在图中创建新的节点和关系。
#### 6.2.1 创建节点
创建节点的基本语法是 `CREATE (变量:标签 {属性: 值})`。
- **变量 (Variable)**: 如 `pork`,是一个临时名称,用于在同一条语句中引用该节点。如果后续不需要引用,可以省略。
- **标签 (Label)**: 如 `Ingredient`,用于对节点进行分类。
- **属性 (Properties)**: 一个包含键值对的 map/字典,用于描述节点的具体信息。
最基础的创建语句包含一个临时变量(`pork`)、一个标签(`Ingredient`)和一组属性。
```cypher
CREATE (pork:Ingredient {name:'猪肉', category:'肉类', origin:'杭州'});
```
如果在创建后不需要立刻使用这个节点(例如,在同一查询中创建关系),可以省略临时变量名,这样语法更简洁。
```cypher
CREATE (:Ingredient {name:'土豆', category:'蔬菜', origin:'北京'});
```
还可以在创建节点后,使用 `RETURN` 子句立即将其返回。这对于调试或确认节点是否按预期创建非常有用。`RETURN n` 会在结果面板中直接显示刚刚创建的 `鸡蛋` 节点的信息。
```cypher
CREATE (n:Ingredient {name:'鸡蛋'}) RETURN n;
```
执行上述三条命令后,数据库中就创建了三个 `Ingredient` 类型的节点。能够通过 Neo4j Browser 的可视化界面直观地看到这些新创建的数据。
<div align="center">
<img src="images/2_2_1_1.png" alt="创建节点后的数据库信息" width="100%" />
<p>图 2.5: 执行创建命令后,左侧面板显示已有 3 个 Ingredient 节点</p>
</div>
点击左侧面板中的 `Ingredient` 标签,Neo4j Browser 会自动执行 `MATCH (n:Ingredient) RETURN n LIMIT 25;` 查询,并在主窗口中展示所有食材节点。如图 2.6 所示,点击其中一个节点(如“土豆”),右侧会显示其详细属性。这里可以观察到:
- **`<id>` 字段**:这是 Neo4j 为每个节点自动生成的内部唯一标识符。
- **Key-Value 结构**:右侧的 “Key” 和 “Value” 两列展示了节点属性是以键值对的形式存储的。
- **自定义属性**`name`、`category`、`origin` 三个字段的值与前面 `CREATE` 语句中设定的值完全一致。
<div align="center">
<img src="images/2_2_1_2.png" alt="查询并查看节点详情" width="100%" />
<p>图 2.6: 查询并查看新创建的节点及其属性</p>
</div>
#### 6.2.2 创建关系
关系的创建通常需要先指定关系两端的节点,然后用 `-[变量:类型 {属性}]->` 来定义关系。
- 关系必须有 **方向** 和 **类型 (Type)**。
- 小括号 `()` 用于表示节点,中括号 `[]` 用于表示关系。
在实际应用中,常常需要一次性创建多个节点以及它们之间的关系。`CREATE` 语句支持通过逗号分隔,在一个查询中完成复杂图谱的构建。下面的例子将创建一个更复杂的菜品关系网络,以体现“多对多”的特性(一道菜包含多种食材,一种食材可用于多道菜)。
```cypher
CREATE
// 创建食材节点
(rousi:Ingredient {name:'猪里脊'}),
(muer:Ingredient {name:'木耳'}),
(huluobo:Ingredient {name:'胡萝卜'}),
(qingjiao:Ingredient {name:'青椒'}),
// 创建菜品节点
(d1:Dish {name:'鱼香肉丝', cuisine:'川菜'}),
(d2:Dish {name:'木须肉', cuisine:'鲁菜'}),
// 创建关系
(d1)-[:包含 {amount:'250g'}]->(rousi), (d1)-[:包含]->(muer), (d1)-[:包含]->(huluobo),
(d2)-[:包含 {amount:'150g'}]->(rousi), (d2)-[:包含]->(muer),
// 创建双向关系
(rousi)-[:被用于]->(d1), (muer)-[:被用于]->(d1), (huluobo)-[:被用于]->(d1),
(rousi)-[:被用于]->(d2), (muer)-[:被用于]->(d2);
```
这个查询语句做了以下几件事:
1. **创建了 4 个 `Ingredient` 节点**:猪里脊、木耳、胡萝卜、青椒。
2. **创建了 2 个 `Dish` 节点**:鱼香肉丝、木须肉。
3. **创建了 5 条 `包含` 关系**:从菜品指向食材。
4. **创建了 5 条 `被用于` 关系**:从食材指向菜品。这样既可以方便地查询“一道菜包含哪些食材”,也可以高效地反向查询“一种食材被用在了哪些菜里”。
执行 `MATCH p=()-[:包含]->() RETURN p LIMIT 25;` 查询可以可视化展示所有“包含”关系。点击关系(箭头),可以在右侧看到其详细信息,例如“鱼香肉丝”到“猪里脊”的关系上,就包含了在 `CREATE` 语句中定义的 `amount: '250g'` 这一属性。
<div align="center">
<img src="images/2_2_2_1.png" alt="同时创建节点和关系后的图谱" width="100%" />
<p>图 2.7: 创建关系后的图谱结构</p>
</div>
### 6.3 查询 (MATCH)
`MATCH` 是 Cypher 中用于查询图数据的命令,它允许你描述你想要寻找的节点和关系的模式。
#### 6.3.1 基本查询
最简单的查询是匹配并返回图中的任意节点,可以使用 `LIMIT` 关键字限制返回数量,避免因数据量过大导致浏览器卡顿。
```cypher
// 匹配并返回图中的任意 25 个节点
MATCH (n)
RETURN n
LIMIT 25;
```
也可以根据标签和属性进行精确匹配。
```cypher
// 匹配所有标签为 Ingredient,且名字为'猪里脊'的节点
MATCH (n:Ingredient {name:'猪里脊'}) RETURN n;
```
#### 6.3.2 条件查询 (WHERE)
`WHERE` 子句提供了更灵活的过滤能力,可以对节点的属性进行复杂的逻辑判断。
例如,查询名字是'猪里脊'或'鸡蛋'的 `Ingredient` 节点。
```cypher
MATCH (n:Ingredient)
WHERE n.name IN ['猪里脊','鸡蛋']
RETURN n;
```
也可以使用 `AND`、`OR` 等关键字构建复合查询条件。
```cypher
// 复合条件:查询指定名称且类别为“肉类”的节点
MATCH (n:Ingredient)
WHERE n.name IN ['猪肉', '猪里脊', '鸡蛋'] AND n.category = '肉类'
RETURN n;
```
#### 6.3.3 返回指定属性
默认情况下,`RETURN n` 会返回整个节点对象。也可以只返回节点的特定属性,并使用 `AS` 为返回的列起别名,使结果更具可读性。
```cypher
MATCH (n:Ingredient)
WHERE n.name IN ['猪里脊','鸡蛋']
RETURN n.name AS 食材名称, n.category AS 类别;
```
#### 6.3.4 关联查询
图数据库最强大的地方在于对关系的查询。例如,可以一次性查询“鱼香肉丝”和“木须肉”分别包含了哪些食材。
```cypher
MATCH (d:Dish)-[:包含]->(i:Ingredient)
WHERE d.name IN ['鱼香肉丝', '木须肉']
RETURN d.name AS 菜品, collect(i.name) AS 食材列表;
```
> `collect()` 是一个聚合函数,可以将匹配到的多个同类结果(这里是食材名称 `i.name`)收集到一个列表中。
#### 6.3.5 查询并创建 (MATCH + CREATE)
在实际应用中,一个常见的操作是先找到图中已经存在的节点,然后为它们添加新的关系。这可以通过组合使用 `MATCH` 和 `CREATE` 来实现。
例如,我们已经创建了“鱼香肉丝”和“猪里脊”,现在想为它们添加一条“主要食材”的关系。
```cypher
MATCH
(d:Dish {name:'鱼香肉丝'}),
(i:Ingredient {name:'猪里脊'})
MERGE
(d)-[r:主要食材]->(i)
RETURN d, i, r;
```
> 这个模式确保了是在已有的、正确的实体之间建立关联,并通过 `MERGE` 避免重复的关系。
#### 6.3.6 排序 (ORDER BY)
可以使用 `ORDER BY` 子句对返回的结果进行排序。默认是升序 (`ASC`),也可以指定为降序 (`DESC`)。
```cypher
// 查询所有食材,并按名称升序排序
MATCH (i:Ingredient)
RETURN i.name, i.category
ORDER BY i.name ASC;
```
### 6.4 更新 (SET & MERGE)
#### 6.4.1 更新属性 (SET)
`SET` 语句用于修改或添加节点/关系的属性。它必须和 `MATCH` 配合使用,先找到要更新的实体,再进行修改。
```cypher
MATCH (i:Ingredient {name:'猪肉'})
SET
i.is_frozen = true,
i.origin = '金华'
RETURN i;
```
#### 6.4.2 插入或更新 (MERGE)
在构建知识图谱时,经常遇到这样的场景:如果某个节点已存在,则更新其属性;如果不存在,则创建它。`MERGE` 语句就可以解决这个问题。
`MERGE` 会根据你提供的模式在图中查找,如果找到匹配项,则执行 `ON MATCH` 部分;如果未找到,则执行 `ON CREATE` 部分,从而避免了重复创建实体。
```cypher
// 查找名为'大蒜'的 Ingredient 节点
MERGE (n:Ingredient {name: '大蒜'})
// 如果不存在,则创建该节点,并设置创建时间和初始库存
ON CREATE SET
n.created = timestamp(),
n.stock = 100
// 如果已存在,则更新其库存、访问次数和访问时间
ON MATCH SET
n.stock = coalesce(n.stock, 0) - 1,
n.counter = coalesce(n.counter, 0) + 1,
n.accessTime = timestamp()
RETURN n;
```
> `coalesce(property, defaultValue)` 是一个非常有用的函数,它会检查属性 `property` 是否存在,如果存在则返回其值,否则返回 `defaultValue`。
### 6.5 删除 (DELETE & REMOVE)
#### 6.5.1 删除属性 (REMOVE)
`REMOVE` 用于移除节点或关系上的某个属性。在下面的例子中,先用 `MATCH` 找到名为“大蒜”的节点,然后移除由 `MERGE` 命令在创建它时添加的 `created` 属性。
```cypher
MATCH (i:Ingredient {name:'大蒜'})
REMOVE i.created
RETURN i;
```
#### 6.5.2 删除节点和关系 (DELETE)
`DELETE` 用于删除节点和关系。但需要 **特别注意**:Neo4j 不允许直接删除一个还存在关联关系的节点。你必须先删除关系,才能删除节点。
```cypher
// 错误示范:如果'大蒜'还有关系连着,这条语句会报错
MATCH (i:Ingredient {name:'大蒜'})
DELETE i;
```
正确的做法有两种。第一种是先手动删除与节点相关的所有关系,然后再删除节点本身。
```cypher
// 正确做法 1:先删除关系,再删除节点
MATCH (i:Ingredient {name:'大蒜'})-[r]-() // 匹配与'大蒜'相连的任意关系
DELETE r, i; // 先删除关系 r,再删除节点 i
```
第二种做法更简洁,也是官方推荐的方式:使用 `DETACH DELETE`。它会自动删除指定节点以及所有与它直接相连的关系。
```cypher
// 正确做法 2:使用 DETACH DELETE (推荐)
MATCH (i:Ingredient {name:'大蒜'})
DETACH DELETE i;
```
此外,还可以通过节点的内部 ID 进行精确查找和删除。每个节点都有一个由 Neo4j 自动分配的唯一 ID,可以通过 `id()` 函数获取。
```cypher
// 假设我们通过查询得知“大蒜”的 ID 为 5
MATCH (i:Ingredient)
WHERE id(i) = 5
DETACH DELETE i;
```
#### 6.5.3 清空数据库
如果想删除数据库中的所有节点和关系,可以使用以下命令:
```cypher
// 匹配所有节点 n
MATCH (n)
// 强制删除节点 n 及其所有关系
DETACH DELETE n;
```
#### 6.5.4 软删除
在生产环境中,直接从数据库中物理删除(`DELETE`)数据是一种高风险操作。一种更安全、更常见的做法是“软删除”。软删除并非真的将数据移除,而是通过 `SET` 命令为其添加一个状态属性,将其标记为“已删除”或“不活跃”。
```cypher
// 将“木耳”标记为不活跃
MATCH (i:Ingredient {name:'木耳'})
SET i.is_active = false;
```
这样,在后续的查询中,只需要增加一个 `WHERE i.is_active = true` 的过滤条件,就能只使用那些“活跃”的数据,而被软删除的数据依然保留在数据库中,以备审计或恢复。
> 删除操作是高风险行为,尤其是在生产环境中。执行前请务必确认操作对象和范围,并做好数据备份。