什么是图数据库(graph database)
图数据库是基于图论实现的一种NoSQL数据库,其数据存储结构和数据查询方式都是以图论为基础的,图数据库主要用于存储更多的连接数据。
什么是Neo4j
Neo4j是一个开源的NoSQL图形数据库,2003年开始开发,使用scala和java语言,2007年开始发布。
- 是世界上最先进的图数据库之一,提供原生的图数据存储,检索和处理
- 采用属性图模型(Property graph model),极大地完善和丰富图数据模型
- 专属查询语言Cypher,直观。高效
属性图模型
Neo4j图数据库遵循属性图模型来存储和管理其数据
属性图模型规则:
- 表示节点,关系和属性中的数据
- 节点和关系都包含属性
- 关系连接节点
- 属性是键值对
- 节点用圆圈表示,关系用方向键表示
- 关系具有方向:单向和双向
- 每个关系包含“开始节点”或“从节点”和“到节点”或“结束节点”
在属性图数据模型中,关系应该是定向的。
Neo4j图数据库将其所有数据存储在节点和关系中,我们不需要任何额外的RDBMS数据库或NoSQL数据库来存储Neo4j数据库数据,它以图的形式存储数据,Neo4j使用本机GRE(图形处理引擎)来使用它的本机图存储格式
图数据库模型的主要构建块是:- 节点
- 关系
- 属性
简单的属性图的例子:
Neo4j的构建元素
Neo4j图数据库主要有以下构建元素:
- 节点
- 属性
- 关系
- 标签
- 数据浏览器
节点
节点(Node)是图数据库中的一个基本元素,用来表示一个实体记录,就像关系数据库中的一条记录一样。在Neo4j中节点可以包含多个属性(Properties)和多个标签(Label)
1. 节点是主要的数据元素
2. 节点通过关系连接到其他节点
3. 节点可以具有一个或多个属性(即,存储为键/值对的属性)
4. 节点有一个或多个标签。用于描述其在图表中的作用
属性
属性(Property)是用于描述图节点和关系的键值对,其中key是一个字符串,值可以通过使用任何Neo4j数据类型来表示
- 属性是命名值,其中名称(或键)是字符串
- 属性可以被索引和约束
- 可以从多个属性创建复合索引
关系
关系(Relationship)同样是图数据库的基本元素。当数据库中已经存在节点后,需要将节点连接起来构成图,关系就是用来连接两个节点,关系也称为图论的边(Edge),其始端和末端都必须是节点,关系不能指向空也不能从空发起。关系和节点一样可以包含多个属性,但关系只能有一个类型(Type)
- 关系连接两个节点
- 关系是方向性的
- 节点可以有多个甚至递归的关系
- 关系可以有一个或多个属性(即存储为键值对的属性)
基于方向性,Neo4j关系被分为两种主要类型:- 单向关系
- 双向关系
标签
标签(Lavel)将一个公共名与一组节点或关系相关联,节点或关系可以包含一个或多个标签。我们可以为现有节点或关系创建新标签,我们可以从现有节点或关系中删除标签。
- 标签用于将节点分组
- 一个节点可以具有多个标签
- 对标签进行索引可以加速在图中查找节点
- 本机标签索引对速度进行了优化
Neo4j Browser
一旦安装了Neo4j,我们就可以访问Neo4j的数据浏览器
CQL使用
CQL简介
Neo4j的Cypher语言是为处理图形数据库而构建的,CQL代表Cypher查询语言。
- 他是Neo4j图形数据库的查询语言
- 他是一种声明性模式匹配语言
- 它遵循SQL语法
- 他的语法非常简单且人性化,可读的格式
CQL命令 | 用法 |
---|---|
CREATE | 创建节点,关系和属性 |
MATCH | 检索有关节点,关系和属性数据 |
RETURN | 返回查询结果 |
WHERE | 提供条件过滤检索数据 |
DELETE | 删除节点和关系 |
REMOVE | 删除节点和关系的属性 |
ORDER BY | 排序检索数据 |
SET | 添加或更新标签 |
三个共同朋友的社交圈:
使用cypher语言来描述关系:
(fox)<-[:knows]-(周瑜)-[:knows]->(诸葛)-[:knows]->(fox)
CQL命令
Load
# 将csv拷贝到%Neo4J_HOME%\import目录
load csv from 'file:///西游记.csv' as line
create (:西游 {name:line[0],tail:line[1],label:line[3]})
CREATE
create语句是创建模型语句用来创建数据模型
创建节点
create命令可以用于创建节点,有两种语法,分别对应创建无属性的节点和有属性的节点。
//无属性
create (<node-name>:<label-name>)
//有属性
create (
<node-name>:<label-name>
{
<Property1-name>:<Property1-Value>
........
<PropertyN-name>:<PropertyN-Value>
}
)
create也可以创建一个节点对应多个标签,语法为:
create (<node-name>:<label-name1>:<label-name2>.....:<label-nameN>)
# 示例
create (xiaobai:Boy:Student:Person)
//这里xiaobai是节点名,Boy、Student、Person是该节点的多个标签名称
create还可以用于创建节点之间的关系,语法为:
create (<node1-name>:<label1-name>)-
[<relationship-name>:<relationship-label-name>]
->(<node2-name>:<label2-name>)
# relationship-name是要创建的关系的具体名称,relationship-label-name是关系的标签名称。
# 具体示例如下,创建了两个节点,并且从节点b1到g1有一个单向的关系
create (b1:Boy)-[r1:Likes]->(g1:Girl)
# 注意,Neo4j中两个节点之间的关系是有方向性的,使用了箭头进行标记:() - []→()。如果没有使用箭头标记关系的方向:() - [] - (),那么Neo4j服务器会报错
match+return
# match命令语法为:
match
(
<node-name>:<label-name>
)
这里有个很重要的注意事项,不能单独使用match语句,必须和其他语句进行配合。如果单独使用match,系统将报错InvalidSyntax,我们使用时match经常与return配合。
# return命令语法为:
return
<node-name>.<property1-name>,
······
<node-name>.<propertyN-name>
return语句也是不能单独使用的,应该与match或者create语句配合。
match配合return语句示例:
//检索Student标签下xiaoming节点的某几个属性
match (xiaoming:Student)
return xiaoming.id, xiaoming.age
//检索Student标签下xiaoming节点的所有属性
match (xiaoming:Student)
return xiaoming
where
where命令的用法和SQL完全一样,就是通过限制条件来过滤数据
//简单where
where <condition>
//复杂where
where <condition> <boolean-operator> <condition>
condition就是筛选条件,包括小于、大于、小于等于、大于等于、等于、不等于六种选择,例如 id>100,age<=20 等。值得注意的是,不等于用 <> 来进行表示。
boolean-operator就是布尔运算符,包括 AND、OR、NOT、XOR 四种,分别对应与、或、非、异或四种操作。
示例如下,假设现在数据库中有2个年龄20岁和2个年龄21岁的学生(标签Student),名字分别是zhangsan、lisi、zhangsan、lisi。
//查询年龄为21的学生
match (stu:Student)
where stu.age=21
return stu
//查询年龄为20且名字为zhangsan的学生
match (stu:student)
whhere stu.age=20 and stu.name="zhangsan"
return stu
delete
delete的删除方式有两种,一种是直接删除节点,但是要求删除的节点不能与其他节点有关系连接;另一种是将节点和关系一起删除。
//删除节点
delete <node-namelist>
//删除节点及其关系
delete <node1-name>,<node2-name>,<relationship-name>
remove
delete与remove的相同点:
1. 两者都不能单独使用
2. 两者都应该和match命令配合使用
delete和remove的不同点:
1. delete用于删除节点和关系
2. remove用于删除标签和属性
remove语法:
//删除节点或关系的属性
remove <property-name-list>
//删除节点或关系的标签
remove <label-name-list>
示例如下:
/先创建节点
create (stu1:Student {sid:003,name:"xiao bai",age:19,dept:"SE"})
create (xiaohong:Girl:Student:Person)
//删除“dept”属性
match (stu1{sid:003})
remove stu1.dept
return stu1
//删除student、person标签
match (xiaohong:Girl)
remove xiaohong:Student,xiaohong:Person
set
//添加/更新属性
set <property-name-list>
示例如下
//先创建节点
create (stu2:Student {sid:004,name:"xiao gang",age:20,dept:"SE"})
//添加属性class
match (stu2:Student)
where stu2.dept="SE"
set stu2.class = "SE01"
return stu2
//已经存在属性class,则会将其更改为SE02
match (stu2:Student)
where stu2.dept="SE"
set stu2.class = "SE02"
return stu2
order by
order by命令可以对match查询的结果进行排序,默认是升序排序。语法如下:
//升序
ORDER BY <property-name-list>
//降序使用关键字 desc
ORDER BY <property-name-list> desc
示例如下,假设数据库中存在5本书(标签Book),id分别为001至005,price分别是20、40、30、50、10
//按价格升序,获取前三个节点
match (book:Book)
return book
order by book.price
limit 3
//按id降序
match (book:Book)
return book
order by book.id desc
merge
我们知道,create命令一定会创建节点,因此当我们想判断某个节点是否存在时,需要先使用match进行查询;如果存在就不用重复创建,如果不存在再使用create命令创建。
对于这种情况我们可以使用merge命令,merge命令其实就是create命令和match命令的结合。
merge命令的语法和create命令一模一样。但是merge的作用是,如果当前查询节点的属性存在,则不创建新的节点,如果属性不存在就创建新节点。
//创建新节点
merge (t1:Test{id:001, name:"hhh"})
//查询到属性值存在,不会创建节点
merge (t2:Test{name:"hhh"})
merge (t2:Test{id:001})
//查询到属性值不同,创建新节点
merge (t3:Test{id:002,name:"hhh"})
merge (t4:Test{id:003,name:"go"})
聚合函数
聚合函数的用法和SQL中完全一致
函数 | 效果 |
---|---|
count | 统计match命令返回的行数 |
max | 找到match命令返回的一组行中的最大值 |
min | 找到match命令返回的一组行中的最小值 |
sum | 统计match命令返回的一组行的值求和 |
avg | 统计match命令返回的一组行的值求平均值 |
count(<value>) //<value>可以是*,节点或关系标签名称或属性名称
max(<property-name>)
min(<property-name>)
sum(<property-name>)
avg(<property-name>)
示例如下,假设数据库中存在5本书(标签Book),id分别为001至005,price分别是20、40、30、50、10
//结果为5
match (book:Book) return count(*)
//结果为50、10、150、50
match (book:Book)
return max(book.price),min(book.price),sum(book.price),avg(book.price)
Relationship
CQL的关系函数可以在获取开始节点,结束节点等细节时知道该关系的细节。
函数 | 效果 |
---|---|
startnode | 获取关系的开始节点 |
endnode | 获取关系的结束节点 |
id | 获取关系的ID |
type | 获取关系的类型信息 |
这里的 id 就是我们在create命令中提到的内部ID。
函数语法如下:
relationship-label-name是来自节点或关系的属性名称
relationship-name是关系名称
startnode (<relationship-label-name>)
endnode (<relationship-label-name>)
id (<relationship-name>)
type (<relationship-name>)
示例关系
//先创建关系
create (b101:Boy)-[r101:Likes]->(g101:Girl)
create (s201:Student)-[r201:Read]->(b201:Book)
//获取指定关系的开始和结束节点
match (b)-[r:Likes]->(g)
return startnode(r),endnode(r)
//获取指定关系的id和type
match (s)-[r:Read]->(b)
return id(r),type(r)
//如果不指定关系,那么将会把所有类型的关系都查询出来
match (b)-[r]->(g)
return id(r),type(r)