看完《低智商犯罪》,学习Cypher构建知识图谱
看完《低智商犯罪》,学习Cypher构建知识图谱
摘要
《低智商犯罪》都看了吧,是否现在还在回味剧情里每一个人物的刻画,以及每一个案件的编排。看完后咱们就来简单的学习一下,如何把剧集里的人,事件以及各种关系,构建成一个简单的知识图谱。

首先来看下构建的大致效果:

本文完整脚本的下载:
https://github.com/microsoftbi/RAGHUSKY/blob/main/Documents/dzs_knowledge_graph.cypher
以及测试文本的下载:
https://github.com/microsoftbi/RAGHUSKY/blob/main/Documents/DZS_Story.md
1. 核心概念
1.1 图数据库三要素
节点 (Node) ──→ 实体(人、案件、物品、地点、组织)
关系 (Relationship) ──→ 实体之间的连接(调查、杀害、拥有、隶属)
属性 (Property) ──→ 节点和关系上的键值对(name、role、note)
1.2 Cypher 语法基本模式
Cypher 用 ASCII 艺术描述图模式,这是它最核心的设计思想:
// 节点: (变量:标签 {属性})
(p:Person {name: '张一昂'})
// 关系: -[变量:关系类型 {属性}]->
(a)-[:KNOWS {since: 2020}]->(b)
// 方向: → 有向, - 无向
()-->() // 有向关系
()--() // 无向关系(查询时忽略方向)
1.3 图模型的构建
┌──────────┐ INVESTIGATES ┌──────────┐
│ Person │ ─────────────────→│ Case │
└──────────┘ └──────────┘
│ │
│ BELONGS_TO │ HAPPENED_AT
↓ ↓
┌──────────┐ ┌──────────┐
│Organization│ │ Location │
└──────────┘ └──────────┘
│ │
│ CONTROLS │ DIED_AT
↓ ↓
┌──────────┐ CLUE_TO ┌──────────┐
│ Person │ ←────────────────│ Evidence │
└──────────┘ └──────────┘
5 种节点标签:Person、Case、Organization、Location、Evidence
20+ 种关系类型:SUPERIOR_TO、KILLED、INVESTIGATES、CLUE_TO、BELONGS_TO 等
2. 约束与索引
2.1 唯一性约束 (Uniqueness Constraint)
CREATE CONSTRAINT person_name IF NOT EXISTS
FOR (n:Person) REQUIRE n.name IS UNIQUE;
语法拆解:
| 部分 | 含义 |
|---|---|
CREATE CONSTRAINT person_name |
创建名为 person_name 的约束 |
IF NOT EXISTS |
幂等保护:已存在则跳过(Neo4j 4.4+) |
FOR (n:Person) |
约束作用于 Person 标签的节点 |
REQUIRE n.name IS UNIQUE |
要求 name 属性值唯一 |
为什么需要约束?
- 保证
MERGE能正确匹配已有节点(否则可能创建重复节点) - 自动创建索引,加速
MATCH查询 - 数据完整性保障
2.2 约束 vs 索引
-- 约束(自动附带索引)
CREATE CONSTRAINT ... REQUIRE ... IS UNIQUE -- 唯一性约束
CREATE CONSTRAINT ... REQUIRE ... IS NODE KEY -- 节点键约束(同时唯一+非空)
-- 纯索引(不含约束语义,仅加速查询)
CREATE INDEX person_role FOR (n:Person) ON (n.role);
CREATE TEXT INDEX person_note FOR (n:Person) ON (n.note); -- 全文索引
2.3 查看与删除
SHOW CONSTRAINTS;
SHOW INDEXES;
DROP CONSTRAINT person_name;
3. 创建节点
3.1 MERGE + SET 模式
脚本中大量使用的模式:
MERGE (p1:Person {name: '张一昂'})
SET p1.role = '刑警',
p1.identity = '执法人员',
p1.org = '省公安厅',
p1.note = '主角,五年前因破案意外被调离刑侦一线,后重新启用';
为什么拆成 MERGE + SET?
-- ❌ 错误写法:将所有属性放入 MERGE
MERGE (p:Person {name: '张一昂', role: '刑警', note: '主角...'});
-- 问题:如果节点已存在但 role 不同,MERGE 会创建新节点(因为整体模式不匹配)
-- ✅ 正确写法:只用唯一键做 MERGE,其余用 SET
MERGE (p:Person {name: '张一昂'}) -- 只用唯一键匹配
SET p.role = '刑警', -- SET 总是更新
p.note = '主角...';
核心原则:MERGE 子句中只放唯一标识属性(受约束保护的字段),其余属性用 SET 单独设置。
3.2 MERGE vs CREATE
| MERGE | CREATE | |
|---|---|---|
| 重复执行 | 不创建重复 | 每次创建新节点 |
| 匹配已有 | 先查再决定 | 不查直接建 |
| 适用场景 | 构建脚本(幂等) | 明确要新增 |
-- MERGE: 脚本可重复运行
MERGE (p:Person {name: '张一昂'});
-- CREATE: 每次都生成重复数据(除非确定数据不存在)
CREATE (p:Person {name: '张一昂'});
3.3 多属性 SET 语法
-- 方式1: 逗号分隔(脚本中使用的格式)
SET n.prop1 = 'value1',
n.prop2 = 'value2',
n.prop3 = 'value3';
-- 方式2: 映射批量设置
SET n += {prop1: 'value1', prop2: 'value2', prop3: 'value3'};
-- 方式3: 从已有节点复制
MATCH (a:Person {name: '张一昂'}), (b:Person {name: '李茜'})
SET b.org = a.org; -- 复制 org 属性
3.4 变量命名惯例
MERGE (p1:Person {name: '张一昂'}) -- p1, p2, p3... 人物
MERGE (c1:Case {name: '卢正车祸案'}) -- c1, c2, c3... 案件
MERGE (o1:Organization {name: '省公安厅'}) -- o1, o2... 组织
MERGE (l1:Location {name: '三江口市'}) -- l1, l2... 地点
MERGE (e1:Evidence {name: '残缺举报信'}) -- e1, e2... 证据
变量只在当前语句有效,不需要跨语句保持一致——但良好的命名约定有助于脚本可读性。
4. 创建关系
4.1 核心模式:MATCH + MERGE
MATCH (a:Person {name: '高栋'}), (b:Person {name: '张一昂'})
MERGE (a)-[:SUPERIOR_TO {note: '副厅长→下属'}]->(b);
三步分解:
Step 1: MATCH (a:Person {name: '高栋'}) → 找到起始节点赋给变量 a
Step 2: MATCH (b:Person {name: '张一昂'}) → 找到目标节点赋给变量 b
Step 3: MERGE (a)-[:SUPERIOR_TO]->(b) → 创建/匹配关系
为什么不是 MATCH ... CREATE?
-- ❌ 每次运行都创建重复关系
MATCH (a:Person {name: '高栋'}), (b:Person {name: '张一昂'})
CREATE (a)-[:SUPERIOR_TO]->(b);
-- ✅ 幂等安全
MATCH (a:Person {name: '高栋'}), (b:Person {name: '张一昂'})
MERGE (a)-[:SUPERIOR_TO]->(b);
4.2 关系方向
(a)-[:SUPERIOR_TO]->(b) // a 是 b 的上级(有向)
(a)-[:COLLEAGUE_WITH]-(b) // a 和 b 互为同事(无向)
// 实际使用中,方向取决于语义:
// 张一昂 调查→ 案件:有意义的方向
// 张一昂-同事-李茜:双向等同,但存储时仍需选一个方向,查询时可用 ()--() 忽略方向
4.3 同标签节点间的关系(Person ↔ Person)
脚本 Part 7 中全部是 (Person)-[:REL_TYPE]->(Person) 的模式:
// 上下级:高栋 → 张一昂
MATCH (a:Person {name: '高栋'}), (b:Person {name: '张一昂'})
MERGE (a)-[:SUPERIOR_TO {note: '副厅长→下属'}]->(b);
// 杀害:朗博图 → 叶剑
MATCH (a:Person {name: '朗博图'}), (b:Person {name: '叶剑'})
MERGE (a)-[:KILLED {method: '用绑刀的车撞死', reason: '灭口'}]->(b);
// 勒索:方超 → 周荣
MATCH (a:Person {name: '方超'}), (b:Person {name: '周荣'})
MERGE (a)-[:BLACKMAILED {amount: '2000万', item: '朗博文手机'}]->(b);
同类节点间的关系对照表:
| 关系类型 | 方向 | 示例 |
|---|---|---|
SUPERIOR_TO |
上级→下级 | 高栋→张一昂 |
COLLEAGUE_WITH |
↔ | 张一昂↔李茜 |
SIBLING_OF |
↔ | 朗博文↔朗博图 |
IN_RELATIONSHIP_WITH |
↔ | 陆一波↔周淇 |
COOPERATES_WITH |
↔ | 方超↔刘直 |
KILLED |
凶手→受害者 | 朗博图→叶剑 |
BLACKMAILED |
勒索者→被勒索者 | 方超→周荣 |
COVERED_UP_FOR |
包庇者→被包庇者 | 朗博文→朗博图 |
REPORTED |
举报者→被举报者 | 陆一波→周荣 |
ORDERED |
指使者→执行者 | 周荣→胡建仁 |
ARRESTED |
执法者→被捕者 | 张一昂→李峰 |
FENCED_TO |
销赃者→收赃者 | 方超→郑勇兵 |
TRANSACTED_WITH |
买方→卖方 | 周荣→朱亦飞 |
5. 关系属性
5.1 语法
关系也可以携带属性,语法与节点属性相同:
MERGE (a)-[:KILLED {
method: '用绑刀的车撞死',
reason: '灭口——叶剑发现了手表线索'
}]->(b);
5.2 何时用关系属性 vs 节点属性
| 数据特点 | 放哪里 | 示例 |
|---|---|---|
| 描述关系本身的特征 | 关系属性 | method、amount、role |
| 描述实体自身的特征 | 节点属性 | name、identity、note |
| 关系附加的上下文 | 关系属性 | 勒索金额、抓捕地点 |
| 实体的固有属性 | 节点属性 | 人名、角色、所属组织 |
5.3 脚本中关系属性的实际使用
// 杀害关系:记录手段和动机
[:KILLED {method: '火并枪杀', reason: '朱亦飞指使'}]
// 勒索关系:记录金额和筹码
[:BLACKMAILED {amount: '2000万', item: '朗博文手机'}]
// 指使关系:记录任务内容
[:ORDERED {task: '疏通方庸关系、处理各种事务'}]
// 调查关系:记录角色分工
[:INVESTIGATES {role: '主办'}] // 主办
[:INVESTIGATES {role: '协办'}] // 协办
6. 跨标签关系
6.1 Person → Case(人物 ↔ 案件)
-- 调查
MATCH (a:Person {name: '张一昂'}), (b:Case {name: '叶剑被害案'})
MERGE (a)-[:INVESTIGATES {role: '主办'}]->(b);
-- 被害
MATCH (a:Person {name: '叶剑'}), (b:Case {name: '叶剑被害案'})
MERGE (a)-[:VICTIM_OF]->(b);
-- 供述
MATCH (a:Person {name: '朗博图'}), (b:Case {name: '叶剑被害案'})
MERGE (a)-[:CONFESSED_TO {note: '在机场被截获后供认'}]->(b);
-- 涉案(通用关联,带角色说明)
MATCH (a:Person {name: '陆一波'}), (b:Case {name: '省城爆炸案'})
MERGE (a)-[:INVOLVED_IN {role: '举报人'}]->(b);
Person → Case 关系语义矩阵:
| 关系 | 说明 | 何时使用 |
|---|---|---|
INVESTIGATES |
调查案件 | 执法人员与案件 |
VICTIM_OF |
是案件的受害者 | 死伤者与案件 |
WITNESSED |
目击案件 | 目击者与案件 |
CONFESSED_TO |
供认罪行 | 罪犯与案件 |
SUSPECTED_OF |
涉嫌(不一定真凶) | 嫌疑人(含被冤枉) |
INVOLVED_IN |
通用关联 | 不适合上述分类时使用 |
6.2 Evidence → Case(证据 ↔ 案件)
-- 线索
MATCH (a:Evidence {name: '限量电子表'}), (b:Case {name: '卢正车祸死亡案'})
MERGE (a)-[:CLUE_TO {note: '出现在车祸现场视频中'}]->(b);
-- 凶器
MATCH (a:Evidence {name: '绑刀的车'}), (b:Case {name: '叶剑被害案'})
MERGE (a)-[:WEAPON_OF]->(b);
-- 赃物
MATCH (a:Evidence {name: '假玉财神像'}), (b:Case {name: '省城爆炸案'})
MERGE (a)-[:LOOT_OF]->(b);
6.3 Person → Organization(人物 ↔ 组织)
-- 隶属
MATCH (a:Person {name: '张一昂'}), (b:Organization {name: '省公安厅'})
MERGE (a)-[:BELONGS_TO]->(b);
-- 控制(领导关系)
MATCH (a:Person {name: '周荣'}), (b:Organization {name: '荣城集团'})
MERGE (a)-[:CONTROLS]->(b);
BELONGS_TO vs CONTROLS:
- 普通成员用
BELONGS_TO - 老板/主管用
CONTROLS(暗示对组织的控制权) - 一个人可以同时有两者(如周荣既有
BELONGS_TO也有CONTROLS)
6.4 Case → Case(案件 ↔ 案件)
-- 一个案件引出另一个
MATCH (a:Case {name: '省城爆炸案'}), (b:Case {name: '卢正车祸死亡案'})
MERGE (a)-[:LED_TO {note: '爆炸案现场的举报信引出卢正案重新调查'}]->(b);
-- 案件间的关联
MATCH (a:Case {name: '叶剑被害案'}), (b:Case {name: '卢正车祸死亡案'})
MERGE (a)-[:LINKED_TO {note: '叶剑因重新调查卢正案发现手表线索而被害'}]->(b);
-- 案件是系列案的一部分
MATCH (a:Case {name: '信用社抢劫案'}), (b:Case {name: '方超刘直连环抢劫案'})
MERGE (a)-[:PART_OF]->(b);
6.5 Person → Location(人物 ↔ 地点)
-- 死于某地
MATCH (a:Person {name: '叶剑'}), (b:Location {name: '河岸边'})
MERGE (a)-[:DIED_AT]->(b);
-- 前往某地
MATCH (a:Person {name: '张一昂'}), (b:Location {name: '周荣庄园'})
MERGE (a)-[:WENT_TO {note: '带队查案,最终在此逮捕周荣'}]->(b);
-- 被困某地
MATCH (a:Person {name: '方超'}), (b:Location {name: '枯井'})
MERGE (a)-[:TRAPPED_IN {note: '踩点时掉入枯井被困三天'}]->(b);
-- 在某地受伤
MATCH (a:Person {name: '李棚改'}), (b:Location {name: '涵洞'})
MERGE (a)-[:INJURED_AT {note: '追捕刚哥小毛时失足摔倒昏迷'}]->(b);
附录:脚本速查表
节点标签与数量
| 标签 | 数量 | 示例 |
|---|---|---|
Person |
33 | 张一昂、方超、周荣、叶剑 |
Case |
10 | 卢正车祸案、叶剑被害案、编钟非法交易案 |
Organization |
7 | 省公安厅、荣城集团、枫林晚酒店 |
Location |
15 | 三江口市、周荣庄园、河岸边、枯井 |
Evidence |
12 | 残缺举报信、限量电子表、一昂血字石头 |
关系类型速查
| 关系 | from → to | 说明 |
|---|---|---|
SUPERIOR_TO |
Person→Person | 上下级 |
COLLEAGUE_WITH |
Person→Person | 同事 |
SIBLING_OF |
Person→Person | 兄弟 |
IN_RELATIONSHIP_WITH |
Person→Person | 情侣/夫妻 |
COOPERATES_WITH |
Person→Person | 合作搭档 |
KILLED |
Person→Person | 杀害 |
BLACKMAILED |
Person→Person | 勒索 |
COVERED_UP_FOR |
Person→Person | 包庇顶罪 |
REPORTED |
Person→Person | 举报 |
ORDERED |
Person→Person | 指使命令 |
FENCED_TO |
Person→Person | 销赃 |
TRANSACTED_WITH |
Person→Person | 非法交易 |
ARRESTED |
Person→Person | 抓捕 |
INVESTIGATES |
Person→Case | 调查案件 |
VICTIM_OF |
Person→Case | 被害 |
WITNESSED |
Person→Case | 目击 |
CONFESSED_TO |
Person→Case | 供述 |
SUSPECTED_OF |
Person→Case | 涉嫌 |
INVOLVED_IN |
Person→Case | 涉案关联 |
OWNS |
Person→Evidence | 拥有物品 |
DISCOVERED |
Person→Evidence | 发现证据 |
LEFT_BEHIND |
Person→Evidence | 留下线索 |
USED |
Person→Evidence | 使用物品 |
BOUGHT_STOLEN |
Person→Evidence | 购买赃物 |
BELONGS_TO |
Person→Organization | 隶属组织 |
CONTROLS |
Person→Organization | 控制组织 |
CLUE_TO |
Evidence→Case | 线索指向 |
WEAPON_OF |
Evidence→Case | 凶器 |
LOOT_OF |
Evidence→Case | 赃物 |
LED_TO |
Case→Case | 引出案件 |
LINKED_TO |
Case→Case | 案件关联 |
PART_OF |
Case→Case | 系列案 |
HAPPENED_AT |
Case→Location | 发生地点 |
INVOLVES_ORG |
Case→Organization | 涉及组织 |
DIED_AT |
Person→Location | 死亡地点 |
WENT_TO |
Person→Location | 前往地点 |
TRAPPED_IN |
Person→Location | 被困地点 |
INJURED_AT |
Person→Location | 受伤地点 |
posted on 2026-05-27 13:56 哥本哈士奇(aspnetx) 阅读(105) 评论(0) 收藏 举报
浙公网安备 33010602011771号