前言
今天,我们一起来学习知识图谱中的Neo4J。首先,什么是知识图谱?先摘一段百度百科:
Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。Neo4j也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下而不是严格、静态的表中——但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处。
Neo4j因其嵌入式、高性能、轻量级等优势,越来越受到关注.
Neo是一个网络——面向网络的数据库——也就是说,它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络上而不是表中。网络(从数学角度叫做图)是一个灵活的数据结构,可以应用更加敏捷和快速的开发模式。
简单说来,知识图谱就是通过不同知识的关联性形成一个网状的知识结构,而这个知识结构,恰好就是人工智能AI的基石。当前AI领域热门的计算机图像、语音识别甚至是NLP,其实都是AI的感知能力,真正AI的认知能力,就要靠知识图谱。
知识图谱目前的应用主要在搜索、智能问答、推荐系统等方面。知识图谱的建设,一般包括数据获取、实体识别和关系抽取、数据存储、图谱应用都几个方面。
本文,从Neo4j的数据存储来学习如何使用
一、Neo4J简介
知识图谱由于其数据包含实体、属性、关系等,常见的关系型数据库诸如MySQL之类不能很好的体现数据的这些特点,因此知识图谱数据的存储一般是采用图数据库(Graph Databases)。而Neo4j是其中最为常见的图数据库。
对比关系型数据库:
关系型数据库(RDBMS) | 图数据库 |
表 | 图 |
行 | 节点 |
列和数据 | 属性和数据 |
约束 | 关系 |
对比其他NoSQL数据库
NoSQL数据库大致可以分为四类:
- 键值(key/value)数据库
- 列存储数据库
- 文档型数据库
- 图数据库
二、Neo4J下载安装
方法1:安装Neo4j Community Server
Neo4j和MySQL类似,我们也需要安装一个服务端程序,再安装一个客户端程序,客户端程序不安装直接使用命令行操作也可以。接下来先安装服务端程序。
首先在 https://neo4j.com/download-center// 下载Neo4J。Neo4J分为社区版和企业版,企业版在横向扩展、权限控制、运行性能、HA等方面都比社区版好,适合正式的生产环境,普通的学习和开发采用免费社区版就好。
注意: neo4j最新版对应的java版本是jdk11
jdk8可以下载Neo4j Community Edition 3.5.28
官方文档:https://neo4j.com/docs/operations-manual/3.5/
解压到新目录(注意:目录名称不要有中文),比如: D:\neo4j\
# 将Neo4j作为控制台应用程序运行 <NEO4J_HOME>\bin\neo4j console # 将Neo4j作为服务使用进行安装 <NEO4J_HOME>\bin\neo4j install-service
进入到bin目录,执行
neo4j console: 直接启动 neo4j 服务,
此外,还有其他几个命令:
install-service | uninstall-ser update-service : 安装/卸载/更新 neo4j 服务
start/stop/restart/status: 启动/停止/重启/状态
-V 输出更多信息
启动成功之后就可以在浏览器进行访问了,默认端口号是7474,ip改为服务器地址。
http://localhost:7474
访问成功应该是下图这个页面,能访问到说明正常启动,输入默认用户名neo4j和密码neo4j进行连接。
连接成功后如下图所示:
这个界面很友好,英文好的同学可以根据官方向导开始学习了。而像我这种英文渣渣就只能一步步慢慢摸索了。
安装方法2:直接按照带服务端的客户端
对于初学者来说大多数还都是在Windows系统上进行入门学习,所以我们可以直接下载Windows的客户端运行使用。
这里可以直接下载最新版客户端版本
安装客户端后可以自行选择任何neo4j server版本进行安装,都是界面化操作,安装好server之后可以直接一键启动,启动成功后也可以使用浏览器http://localhost:7474进行连接,也可以使用客户端连接,很方便。
基础工作完成之后,我们开始命令CQL语句的学习。
三:Neo4j Cypher 语言
到这里还是先学习一下Neo4j的数据模型再写CQL吧。
Neo4j数据模型
Neo4j是一个表示关系连接的图数据库,既然是图,那么必然有节点,和连接两个节点之间的关系组成。每个节点相当于一个实体,每个实体都有构成它的属性。
比如刘备和关羽,刘备和关羽都是一个个的实体,都可以称作为一个节点,他们有一个共同的标签:都是人,。他们之间的关系为:兄弟,刘备的属性是仁义、大耳贼、汉皇后裔等等。关羽的属性有:勇猛、忠义等等。
在Neo4j中,数据模型的主要构建块是:
- 节点
- 关系
- 属性
- 标签
节点
节点(Node)是图数据库中的一个基本元素,用来表示一个实体记录,就像关系数据库中的一条记录一 样。在Neo4j中节点可以包含多个属性(Property)和多个标签(Label)。
节点是主要的数据元素,节点通过关系连接到其他节点
节点可以具有一个或多个属性(即,存储为键/值对的属性)
节点有一个或多个标签,用于描述其在图表中的作用
属性
属性(Property)是用于描述图节点和关系的键值对。其中Key是一个字符串,值可以通过使用任何 Neo4j数据类型来表示
- 属性是命名值,其中名称(或键)是字符串
- 属性可以被索引和约束 可以从多个属性创建复合索引
关系
关系(Relationship)同样是图数据库的基本元素。
当数据库中已经存在节点后,需要将节点连接起来构成图。关系就是用来连接两个节点,关系也称为图论的边(Edge) ,其始端和末端都必须是节点,关系不 能指向空也不能从空发起。关系和节点一样可以包含多个属性,但关系只能有一个类型(Type) 。
关系连接两个节点
关系是方向性的
节点可以有多个甚至递归的关系
关系可以有一个或多个属性(即存储为键/值对的属性)
基于方向性,Neo4j关系被分为两种主要类型:
单向关系
双向关系
标签
标签(Label)将一个公共名称与一组节点或关系相关联, 节点或关系可以包含一个或多个标签。 我们可以为现有节点或关系创建新标签, 我们可以从现有节点或关系中删除标签。
- 标签用于将节点分组
- 一个节点可以具有多个标签
- 对标签进行索引以加速在图中查找节点
- 本机标签索引针对速度进行了优化
Cypher 语言
Neo4j的Cypher语言是为处理图形数据而构建的,CQL代表Cypher查询语言。像Oracle数据库具有查询 语言SQL,Neo4j具有CQL作为查询语言。
它是Neo4j图形数据库的查询语言。
它是一种声明性模式匹配语言
它遵循SQL语法。
它的语法是非常简单且人性化可读的格式。
CQL命令 | 用法 |
CREATE | 创建节点,关系和属性 |
MATCH | 检索有关节点,关系和属性数据 |
RETURN | 返回查询结果 |
WHERE | 提供条件过滤检索数据 |
DELETE | 删除节点和关系 |
REMOVE | 删除节点和关系的属性 |
ORDER BY | 排序检索数据 |
SET | 添加或更新标签 |
官方文档命令说明:https://neo4j.com/docs/cypher-manual/3.5/clauses/
CQL命令实战
直接看Cypher的语法会非常枯燥,本文通过一个实际的案例来一步一步学习如何使用Cypher来操作Neo4J。
- 1、创建节点
#创建简单节点 create (n) #创建多个节点 create (n),(m) #创建带标签和属性的人物节点并返回节点 create (n:Person {name:'刘备'}) return n
CREATE是创建操作,n是节点,Person是标签,代表节点的类型。花括号{}代表节点的属性,属性类似Python的字典。这条语句的含义就是创建一个标签为Person的节点,该节点具有一个name属性,属性值是刘备。return n 就是返回当前节点的值
如图所示,在Neo4J的界面上可以看到创建成功的节点。
我们继续来创建三国更多的人物节点,并分别命名:
create (country:shu { name:'刘备'}); create (country:shu { name:'关羽'}); create (country:shu { name:'张飞'}); create (country:shu { name:'诸葛亮'}); create (country:shu { name:'张苞'}); create (country:shu { name:'关平'}); create (country:shu { name:'关兴'}); create (country:shu { name:'韩遂'}); create (country:shu { name:'黄承彦'}); create (country:shu { name:'黄月英'}); create (country:shu { name:'黄忠'}); create (country:shu { name:'姜维'}); create (country:shu { name:'刘禅'}); create (country:shu { name:'刘启'}); create (country:shu { name:'刘胜'}); create (country:shu { name:'刘协'}); create (country:shu { name:'马超'}); create (country:shu { name:'马良'}); create (country:shu { name:'马谡'}); create (country:shu { name:'马腾'}); create (country:shu { name:'孟获'}); create (country:shu { name:'糜芳'}); create (country:shu { name:'糜夫人'}); create (country:shu { name:'庞统'}); create (country:shu { name:'孙尚香'}); create (country:shu { name:'魏延'}); create (country:shu { name:'赵云'}); create (country:shu { name:'诸葛瑾'}); create (country:wei { name:'曹操'}); create (country:wei { name:'曹植'}); create (country:wei { name:'曹丕'}); create (country:wu { name:'孙策'}); create (country:wu { name:'孙权'}); create (country:wu { name:'周瑜'});
查看刚创建的这些节点信息
match(n) return n
这里,MATCH是匹配操作,而小括号()代表一个节点 node(可理解为括号类似一个圆形),括号里面的n为 标识符 。
这里为便于直观感受先使用基本的查询语句,后面再详细讲解。
Neo4J贴心地使用不用的颜色来表示不同类型的节点。
- 接下来创建关系
MATCH (a:shu {name:'刘备'}), (b:shu {name:'关羽'}) MERGE (a)-[:大哥]->(b)
这里的方括号[]即为关系,大哥为关系的类型。注意这里的箭头–>是有方向的,表示是从a到b的关系。 如图,刘备和关羽之间建立了大哥关系,
再使用这个命令查看我们刚才创建的关系,通过Neo4J的可视化很明显的可以看出:
match(n) return n
- 关系也可以增加属性
MATCH (a:shu {name:'刘备'}), (b:shu {name:'张飞'}) MERGE (a)-[:大哥 {since:"桃园结义"}]->(b)
在关系中,同样的使用花括号{}来增加关系的属性,也是类似Python的字典,这里给大哥关系增加了since属性,属性值为“桃园结义”,表示他们建立兄弟关系的时间。
-接下来增加更多的关系
match (p1:shu {name:'刘备'}),(p2:shu{name:'关羽'}) create (p1)- [r:rel {relation:'结义兄弟'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'张飞'}) create (p1)- [r:rel {relation:'结义兄弟'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'马超'}) create (p1)- [r:rel {relation:'主公'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'庞统'}) create (p1)- [r:rel {relation:'主公'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'黄忠'}) create (p1)- [r:rel {relation:'主公'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'赵云'}) create (p1)- [r:rel {relation:'主公'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'魏延'}) create (p1)- [r:rel {relation:'主公'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'法正'}) create (p1)- [r:rel {relation:'主公'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'糜芳'}) create (p1)- [r:rel {relation:'主公'}]->(p2); match (p1:shu {name:'甘夫人'}),(p2:shu{name:'刘备'}) create (p1)- [r:rel {relation:'妻'}]->(p2); match (p1:shu {name:'糜夫人'}),(p2:shu{name:'刘备'}) create (p1)- [r:rel {relation:'次妻'}]->(p2); match (p1:shu {name:'孙尚香'}),(p2:shu{name:'刘备'}) create (p1)- [r:rel {relation:'妻'}]->(p2); match (p1:shu {name:'关羽'}),(p2:shu{name:'关兴'}) create (p1)- [r:rel {relation:'父子'}]->(p2); match (p1:shu {name:'关平'}),(p2:shu{name:'关羽'}) create (p1)- [r:rel {relation:'义子'}]->(p2); match (p1:shu {name:'张飞'}),(p2:shu{name:'张苞'}) create (p1)- [r:rel {relation:'父子'}]->(p2); match (p1:shu {name:'马腾'}),(p2:shu{name:'马超'}) create (p1)- [r:rel {relation:'父子'}]->(p2); match (p1:shu {name:'马腾'}),(p2:shu{name:'韩遂'}) create (p1)- [r:rel {relation:'异性兄弟'}]->(p2); match (p1:shu {name:'马谡'}),(p2:shu{name:'马良'}) create (p1)- [r:rel {relation:'弟弟'}]->(p2); match (p1:shu {name:'糜芳'}),(p2:shu{name:'糜夫人'}) create (p1)- [r:rel {relation:'兄妹'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'诸葛亮'}) create (p1)- [r:rel {relation:'主公'}]->(p2); match (p1:shu {name:'黄月英'}),(p2:shu{name:'诸葛亮'}) create (p1)- [r:rel {relation:'妻'}]->(p2); match (p1:shu {name:'黄承彦'}),(p2:shu{name:'黄月英'}) create (p1)- [r:rel {relation:'父女'}]->(p2); match (p1:shu {name:'姜维'}),(p2:shu{name:'诸葛亮'}) create (p1)- [r:rel {relation:'弟子'}]->(p2); match (p1:shu {name:'诸葛亮'}),(p2:shu{name:'诸葛瑾'}) create (p1)- [r:rel {relation:'兄弟'}]->(p2); match (p1:shu {name:'诸葛亮'}),(p2:shu{name:'诸葛瞻'}) create (p1)- [r:rel {relation:'父子'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'刘禅'}) create (p1)- [r:rel {relation:'父子'}]->(p2); match (p1:shu {name:'甘夫人'}),(p2:shu{name:'刘禅'}) create (p1)- [r:rel {relation:'母子'}]->(p2); match (p1:shu {name:'刘禅'}),(p2:shu{name:'姜维'}) create (p1)- [r:rel {relation:'主公'}]->(p2); match (p1:shu {name:'诸葛瞻'}),(p2:shu{name:'刘禅'}) create (p1)- [r:rel {relation:'女婿'}]->(p2); match (p1:shu {name:'刘备'}),(p2:shu{name:'刘胜'}) create (p1)- [r:rel {relation:'后代'}]->(p2); match (p1:shu {name:'刘胜'}),(p2:shu{name:'刘启'}) create (p1)- [r:rel {relation:'父子'}]->(p2); match (p1:shu {name:'刘启'}),(p2:shu{name:'刘辩'}) create (p1)- [r:rel {relation:'宗亲'}]->(p2); match (p1:shu {name:'刘辩'}),(p2:shu{name:'刘协'}) create (p1)- [r:rel {relation:'让位'}]->(p2); MATCH (p1:wei {name:'曹植'}), (p2:wei {name:'曹操'}) MERGE (p1)-[:儿子]->(p2); MATCH (p1:wei {name:'曹丕'}), (p2:wei {name:'曹操'}) MERGE (p1)-[:儿子]->(p2); MATCH (p1:wei {name:'曹操'}), (p2:wei {name:'曹丕'}) MERGE (p1)-[:父亲]->(p2); MATCH (p1:wei {name:'曹操'}), (p2:wei {name:'曹植'}) MERGE (p1)-[:父亲]->(p2); MATCH (p1:wu {name:'孙策'}), (p2:wu {name:'孙权'}) MERGE (p1)-[:弟弟 {type:"亲情"}]->(p2); MATCH (p1:wu {name:'孙权'}), (p2:wu {name:'孙策'}) MERGE (p1)-[:哥哥 {type:"亲情"}]->(p2) MATCH (p1:wu {name:'周瑜'}), (p2:wu {name:'孙策'}) MERGE (p1)-[:主公 {type:"主从"}]->(p2);
将上面生成的节点和关系语句在neo4j中执行,就可以了。然后查询,就可以看到效果图了,
有点图谱的意思了吧?
篇幅太长了,剩下的详细查询方法,更新,删除,等另起一篇文章写。
拜拜~