基于neo4j的知识图谱实战演示示例 郝伟 2021/03/01 [TOC]
1. 1 简介
本文将通过我的这几年的生活的一个具体的实际,演示知识图谱的构建和应用过程。 注意:本文需要结合neo4j图数据库进行展示,方可看到实际效果,否则以下内容难以理解。 网址:http://192.168.3.232:7474/browser/
2. 2 准备工具
首先,删除相关内容以便于演示:
-- 删除所有的人和单位。
Match (p:`人`) detach delete p ; Match (c:`单位`) detach delete c
3. 3 知识图谱构建
3.1. 3.1 我是高校教师
2007年我进入安徽理工大学,成为一名大学教师并与王军号成为同事。
-- 我在2007-2014年的状态
Create
(hw:人:教师:硕士{name: '郝伟', 性别:'男', 所在城市:'合肥', 生日:'1981/07/13'}),
(wjh:人:教师:博士{name: '王军号', 性别:'男', 所在城市:'淮南'}),
(aust:大学:高校:学校:单位{name:'安徽理工大学'}),
(hw)-[:员工]->(aust),
(wjh)-[:员工]->(aust)
Return hw, wjh, aust
问题:以下三条语句在删除时,效果是否一样?
Match (n:人{name: '郝伟'}) Detach Delete n
Match (n:教师{name: '郝伟'}) Detach Delete n
Match (n:硕士{name: '郝伟'}) Detach Delete n
注意:在neo4j数据库删除节点时,如果节点有关系,需要加 Detach
才可以删除,否则会报错,比如:
Cannot delete node<465739>, because it still has relationships. To delete this node, you must first delete its relationships.
3.2. 3.2 世界上其他一些人
此时时,这个世界上同时还存在其他一些人,暂时与我还没有任何关系。
-- 世界上还发生着很多的人和事
Create
(scb:人{name: '沈传宝', 性别: '男'}),
(mws:人{name:'马维士', 性别:'男', 所在城市:'北京'}),
(ly:人{name:'李岩', 性别:'男', 所在城市:'北京'}),
(lcy:人:教师{name:'李春艳', 性别:'女', 所在城市:'合肥'})
3.3. 3.3 结婚了
2010年结婚了。我的身份增加了一个:丈夫。
-- 结婚了
Match
(hw:人{name: '郝伟'}), (lcy:人{name: '李春艳'})
Set
hw:丈夫, lcy:妻子,
hw.结婚纪念日= '12/28',
lcy.结婚纪念日= '12/28'
CREATE
p1=(hw)-[:丈夫]->(lcy),
p2=(hw)<-[:妻子]-(lcy)
RETURN
p1, p2
3.4. 3.4 儿子出生
2011年儿子出生了,我的身份双增加了:父亲。
-- 我们有孩子了
Match
(hw:人{name:'郝伟'}), (lcy:人{name:'李春艳'})
SET
hw:父亲, lcy:母亲
CREATE
(hcz:人:儿子{name:'郝承志', 性别:'男', 所在城市:'淮南'}),
(hw)-[:父亲{始于:'2011'}]->(hcz),
(hw)<-[:儿子{始于:'2011'}]-(hcz),
(lcy)-[:母亲{始于:'2011'}]->(hcz),
(lcy)<-[:儿子{始于:'2011'}]-(hcz)
RETURN
hw, lcy, hcz
3.5. 3.5 取得博士学位
2014年10月入学2018年9月毕业,总算拿到了博士,身份又增加了。
Match
(hw:人{name: '郝伟'})
Set
hw:博士:学生:留学生
Create
(kut:大学:高校:学校:单位{name:'高知工科大学'}),
(km:人:导师:教授{name:'松崎公纪', 性别:'男', 国籍: '西班牙'}),
(ono:人:学生:留学生{name: 'Onofre Coll Luise', 国籍: '西班牙', 性别:'男'}),
(vd:人:学生:留学生{name: 'Valade Ganblavesi', 国籍: '俄罗斯', 性别:'男'}),
(hw)<-[:博士导师]-(km),
(hw)-[:同学]->(ono),
(hw)-[:师兄弟]->(ono),
(hw)-[:同学]->(vd),
(hw)-[:毕业于{日期: '2018/09/25', 专业: '信息工程', 方向:'大数据与并行计算'}]->(kut),
(vd)-[:毕业于{日期: '2019/03/28', 专业: '分子材料'}]->(kut),
(ono)-[:毕业于{日期: '2019/09/25', 专业: '信息工程', 方向:'图搜索理论'}]->(kut),
(km)-[:员工{类型:'教员'}]->(kut)
RETURN hw, km, ono, vd, kut
3.6. 3.6 华云安成立
2019年7月,华云安成立了。
-- 沈总创建了华云安
Match
(scb:人{name: '沈传宝'})
SET
scb:老板,
scb:员工
Create
(huaun:公司:科技公司:企业:单位{name: '北京华云安信息技术有限公司', 所在城市: '北京'}),
p1=(scb)-[:创建{创建: '2019'}]->(huaun),
p2=(scb)-[:控股{创建: '2019-2021'}]->(huaun),
p3=(scb)<-[:老板{创建: '2019-2021'}]-(huaun),
p4=(scb)-[:员工{类型: '总经理'}]->(huaun)
RETURN p1, p2, p3,p4
3.7. 3.7 成为华云安的员工
身份和关系都增加了。
--我们加入了公司
Match
(hw:人{name: '郝伟'}),
(mws:人{name:'马维士'}),
(ly:人{name:'李岩'}),
(huaun:公司{name: '北京华云安信息技术有限公司'})
Set
hw:员工,
mws:员工,
ly:员工
Create
(hw)-[:员工{类型:'研究员'}]->(huaun),
(mws)-[:员工{类型:'技术总监'}]->(huaun),
(ly)-[:员工{类型:'产品经理'}]->(huaun),
(hw)-[:同事{公司:'北京华云安'}]->(mws),
(hw)<-[:同事{公司:'北京华云安'}]-(mws),
(hw)-[:同事{公司:'北京华云安'}]->(ly),
(hw)<-[:同事{公司:'北京华云安'}]-(ly),
(mws)-[:同事{公司:'北京华云安'}]->(ly),
(mws)<-[:同事{公司:'北京华云安'}]-(ly)
RETURN
hw, mws, ly, huaun
3.8. 3.8 一些更新
-- 公司获得高新企业资质,沈总与电院有合作关系
Match
(scb:人{name: '沈传宝'}),
(huaun:公司{name: '北京华云安信息技术有限公司'})
Set
huaun:高新企业
Create
(lu:人{name:'陆导'}),
(dy:高校:大学:单位:学校:军校:单位{name:'电院'}),
(lu)-[:员工]->(dy),
(scb)-[:合作]->(lu),
(scb)-[:合作]->(dy)
孩子上学了
Match
(hcz:人{name: '郝承志'})
Set
hcz:学生
Create
(hs:学校:小学:单位{name: '淮师附小'}),
(hcz)-[:学生]->(hs)
4. 4 知识应用
4.1. 4.1 查询郝伟的所有同事:直接查询
直接查询查不出沈总。
Match
(hw:人{name: '郝伟'})-[r:同事]->(c:人)
RETURN
c.name
4.2. 4.2 查询郝伟的全部同事:关系推导
同事的定义:在同一家单位共事的员工。 所以,通过所在公司的员工就能查出。
Match
(hw:人{name: '郝伟'})-[:员工]->(:单位)<-[:员工]-(c)
RETURN
c.name
4.3. 4.3 查询郝伟华云安的同事
使用单位的标签而不是Where或属性子句进行限定。
-- 只看华云安的同事
Match
(hw:人{name: '郝伟'})-[:员工]->(:公司)<-[:员工]-(c)
RETURN
c.name
同理,查询郝校在学校的同事只需修改单位的标签为高校
即可。
Match
(hw:人{name: '郝伟'})-[:员工]->(:高校)<-[:员工]-(c)
RETURN
c.name
4.4. 4.4 查询郝承志爸爸的同事
-- 直接查询
Match
p=(hcz:人{name:'郝承志'})-[:儿子]->(:父亲)-[:同事]->(c:人)
RETURN
c.name
-- 注:在CQL中也支持Where子句,但是效率经常不好
Match
p=(hcz:人)-[:儿子]->(:父亲)-[:同事]->(c:人)
Where
hcz.name='郝承志'
RETURN
c.name
-- 根据定义查询
Match
(:学生{name:'郝承志'})-[:儿子]->()-[:员工]->(:单位)<-[:员工]->(c)
RETURN
c.name
4.5. 4.5 查询沈总可能认识的人
暂时分两种情况:
- 直接认识的人:
Match (:人{name:'沈传宝'})-[]->(c1:人) RETURN ID(c1) as id, c1.name as name
- 间接认识的人:
Match (:人{name:'沈传宝'})-[]-(:公司)-[]-(c2:人) RETURN DISTINCT ID(c2) as id, c2.name as name
以上是公开查询的情况,并且这里只查询了两层关系。这里分了两次查询,实际上可以使用Union进行整合,如下所示。 实际上我们可以使用六层理论,查询更多的人,但是随着层数的增加,认识的几率也会大大降低。
Match
(:人{name:'沈传宝'})-[]->(c1:人)
RETURN
ID(c1) as id, c1.name as name
UNION
Match
(:人{name:'沈传宝'})-[]-(:公司)-[]-(c2:人)
RETURN
ID(c2) as id, c2.name as name
注意:结果中有很多重复的内容,Union会自动合并,如果需要全部显示,使用UNION ALL
。
4.6. 4.6 提问
- Onofre 的导师是谁?类似的,松崎教授有几个学生?
- 王军号认识李春艳的几率大吗?
- 安徽理工大学与高知工科大学知道彼此的存在吗?
5. 5 结论与观点
- 结论
- 图数据库中的记录包括节点和关系,都是非常重要的信息
- 节点与关系数据库表对应,但可以方便地表达多重身份且数据唯一
- 关系是图数据库的核心,是信息计算和推导的重要依赖信息
- 与传统关系数据库相比,图数据库更加自由,不依赖于预定义表和结构
- 没有直接关系的实体有机率通过一定的推导算法进行关联
- 观点
- 设计理念发生重大变化:由先设计数据库再添加数据的传统模式 转变为 先添加数据再分析使用数据 图数据库设计是数据决定框架 → 要同时考虑需求和能拿到的数据 → 要提高数据获取能力
- 无时效性或时效性不强的数据需要随着时间的不断积累才会有价值 → 长期的数据收集过程
- 时效性强的数据必需及时更新才会有价值 → 要有相应的数据获取机制
- 在现有的数据之上进行信息推导能够产生信息价值,但是依赖于人的经验和理解
- 新的设计理念过于自由会带来一定的数据冗余 → 适当的冗余能够有助于数据推理