看完《低智商犯罪》,学习Cypher构建知识图谱

看完《低智商犯罪》,学习Cypher构建知识图谱

摘要

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

img

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

img

本文完整脚本的下载:

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 种节点标签PersonCaseOrganizationLocationEvidence

20+ 种关系类型SUPERIOR_TOKILLEDINVESTIGATESCLUE_TOBELONGS_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 节点属性

数据特点 放哪里 示例
描述关系本身的特征 关系属性 methodamountrole
描述实体自身的特征 节点属性 nameidentitynote
关系附加的上下文 关系属性 勒索金额、抓捕地点
实体的固有属性 节点属性 人名、角色、所属组织

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)    收藏  举报

导航