- neo4j由数据库、标签、节点、关系和属性组成
- 上图共有四个节点,每个节点标识一个完整的实体。节点可以理解为表中的每条数据
- Person和Movie是两个标签,可以简单理解为关系数据库的表,和关系型数据库不同的是,一个节点可以属于多个标签,例如刘德华既是一个演员也是歌手
- name、age、title、time为节点的属性,role为关系的属性
- acted_in、directed标识节点直接的关系类型
安装和启动
启动
- 进入bin目录,运行
./neo4j start
,同理,运行stop
停止,可以通过--help
查看所有的命令- 访问
http://localhost:7474
,初始用户名/密码:neo4j/neo4j
- 登陆后,会让修改密码。示例修改为
root
基本使用
- 官方文档:neo4j.com/docs/cypher…
- neo4j.conf参数配置参考地址:neo4j.com/docs/operat…
基本命令
命令 | 描述 |
---|---|
create database name | 创建和启动数据库,仅仅企业版支持,社区版仅仅支持启动一个数据库 |
drop database name | 移除已经存在的数据库,仅仅企业版支持 |
alter database name | 修改已经存在的数据库,仅仅企业版支持 |
start database name | 启动已经停止的数据库 |
stop database name | 停止数据库 |
show database name | 显示数据库状态 |
show databases | 显示所有的数据库 |
show default database | 显示默认数据库 |
show home database | 显示当前数据库 |
CQL
- CQL和SQL类似,是neo4j的数据库增删改查命令
- 通过bin下的
cypher-shell
可进入shell命令行,和浏览器执行效果相同- CQL区分大小写,大写和小写识别为不同的语句
- CQL区分类型,如果节点属性值为int,在查询时使用字符串(例如age='20'),则查询为空
:use database_name
切换数据库- 社区版只能有一个
创建节点
create (节点名:标签名1:标签名2 {属性1:"属性值", 属性2:"属性值2"})
create (节点名)-[:关系名 {属性一:"属性值"}]->(节点名)
- 标签名可以有一个或多个
- 属性也可有一个或多个
- 创建关系时,需要创建节点和关系语句一起写,分开写不会奏效
- 例子
create (liudehua:Actor:Singer{name:"刘德华",address:"Hongkong"})
create (geyou:Actor{name:"葛优",address:"Henan"})
create (fengxiaogang:Actor:Director{name:"冯小刚",address:"BeiJing"})
create (tianxiawuzei:Movie{title:"天下无贼",time:1994})
create (anzhan:Movie{title:"暗战",time:1994})
create (wujiandao:Movie{title:"无间道",time:1994})
create (bingyu:Music{title:"冰雨",time:1994})
create (liudehua)-[:acted_in {role:"男一号"}]->(tianxiawuzei)
create (liudehua)-[:acted_in {role:"男一号"}]->(anzhan)
create (liudehua)-[:acted_in {role:"男一号"}]->(wujiandao)
create (liudehua)-[:sing]->(bingyu)
create (geyou)-[:acted_in]->(tianxiawuzei)
create (fengxiaogang)-[:diected]->(tianxiawuzei)
查询语句
:question:--与
-->
的区别
Match
基本用法
- 使用MATCH进行匹配某个属性的记录,其中返回值可返回部分数据,只需要使用别名.属性名即可返回特定列
MATCH (别名 {name:"属性值"}) return 别名;
- 例如:查找name为刘德华的记录,仅仅返回name和age,如果没有age属性,则返回null
MATCH(res {name: '刘德华'}) return res.name, res.age;
联合查询
- 如果想要查询name为刘德华且他主演的电影时,可以使用关系进行查询,关系可以依次递进,深入查找
match(res {name:"刘德华"}) -[:acted_in]->(res2) return res.name, res.age, res2.title
深入查找
CREATE (john:Person {name: 'John'})
CREATE (joe:Person {name: 'Joe'})
CREATE (steve:Person {name: 'Steve'})
CREATE (sara:Person {name: 'Sara'})
CREATE (maria:Person {name: 'Maria'})
CREATE (maria1:Person {name: 'Maria1'})
CREATE (maria2:Person {name: 'Maria2'})
CREATE (maria3:Person {name: 'Maria3'})
CREATE (maria4:Person {name: 'Maria4'})
CREATE (john)-[:FRIEND]->(joe)-[:FRIEND]->(steve)-[:FRIEND]->(maria1)-[:FRIEND]->(maria3)
CREATE (john)-[:FRIEND]->(sara)-[:FRIEND]->(maria)-[:FRIEND]->(maria2)-[:FRIEND]->(maria4)
- 数据结构为:
- 现要查找John【子节点】的【子节点】中名称为Maria的【子节点】,则使用下面查询语句
MATCH (john {name: 'John'})-[:FRIEND]->()-[:FRIEND]->(msaria {name:'Maria'})-[:FRIEND]->(fof) RETURN john.name, fof;
where
- Match过滤数据,更像是select,CQL也提供了对应的查询语句,where相当于关系型数据库的where
布尔操作
- CQL中有四种布尔运算,即and、or、not、xor(异或运算)
- 和sql不同的是,null也可以参与运算
- null表示不知道是true还是false
- xor和or的区别为,or是只有有一个为true就为true,而xor则是两者相同为false,不同为true
a | b | a and b | a or b | a xor b | not a |
---|---|---|---|---|---|
null | null | null | null | null | null |
null | false | false | null | null | null |
null | true | null | true | null | null |
false | false | false | false | false | true |
true | true | true | true | false | false |
false | true | false | true | true | true |
示例
match (n:Person) where n.name = 'John' return n;
match (n:Person{name:"John"}) return n;
- 以上两个语句返回结果是一致的,都可以理解为查询标签Person中name为John的数据
IN语句
- 和sql类似,只不过要查询的返回使用中括号,而sql使用的是小括号
match (n) where n.name in ['刘德华', '葛优'] return n;
模糊查询
- 模糊搜索使用
=~
来表示,搜索条件使用正则表达式表示,例如:match(n) where n.name =~ '.*德.*' return n;
标签搜索
- 以上例子是通过属性进行搜索,还可以使用标签进行搜索
match(n) where n:Singer return n;
关系搜索
match (n:Person) -[k] ->(f) where k.name = '伙伴' return n;
- 其中,name为关系的属性,也可以直接使用[k:relationship]筛选出某个关系相关的节点
运算函数
starts with
- 以某个字符串开头
ends with
- 以某个字符串结尾
contains
- 是否包含某个字符串
OPtional Match
create (one:Person{name: "成龙"})
create (two:Person{name: "李连杰"})
create (three:Person{name: "周润发"})
create (four:Person{name: "郭富城"})
create (five:Person{name: "张学友"})
create (six:Person{name: "功夫"})
create (seven:Person{name: "喜剧之王"})
create (one)-[:father]->(two)
create (one)-[:acted_in]->(six)
create (two)-[:acted_in]->(six)
create (two)-[:acted_in]->(seven)
create (three)-[:firected]->(seven)
create (four)-[:acted_in]->(six)
create (four)-[:acted_in]->(seven)
create (five)-[:directed]->(six);
- 与match类似,不同之处在于optional match如果找不到节点,则返回null
with
create (one:Person{name: "成龙"})
create (two:Person{name: "李连杰"})
create (three:Person{name: "周润发"})
create (four:Person{name: "郭富城"})
create (five:Person{name: "张学友"})
create (one)-[:knows]->(three)
create (two)-[:blocks]->(two)
create (two)-[:knows]->(four)
create (three)-[:knows]->(four)
create (three)-[:blocks]->(five)
create (five)-[:knows]->(one);
- with可以定义变量提供给下文操作查询操作使用,例如,定义了变量upperCaseName,在where中可以直接参与运算
MATCH (george {name: '郭富城'})<--(otherPerson) WITH otherPerson, toUpper(otherPerson.name) AS upperCaseName WHERE upperCaseName STARTS WITH '周' RETURN otherPerson.name;
- 同时,如果想要传递多个变量,可以使用通配符*传递所有变量
MATCH (person)-[r]->(otherPerson) WITH *, type(r) AS connectionType RETURN person.name, otherPerson.name, connectionType
unwind
- unwind可以将任何的列表展开成行
示例1
将列表[1,2,3,null]展开成每行的第一列
UNWIND [1, 2, 3, null] AS x
RETURN x, 'val' AS y;
示例2
- 先将集合1、1、2、2转换为行,
- 将数据进行去重,最终由两列,即1,2
- 后将两列合并成集合[1,2]
WITH [1, 1, 2, 2] AS coll
UNWIND coll AS x
WITH DISTINCT x
RETURN collect(x) AS setOfVals
- 示例3
- 先将列表展开为[1,2]、[3,4]和5三行
- 将行展开成1,2,3,4,5 五行
with [[1,2],[3,4], 5] as x
unwind x as y
unwind y as z
return z;
skip
- skip定义了从哪一行数据开始输出,配合limit,可实现分页查询
- 默认从0开始,skip 1表示从第二行开始输出
更新语句
create
创建新节点
create(节点名 [:标签1][:标签2]...{属性1:属性值,属性2:属性值...}),(节点名 [:标签1][:标签2]...{属性1:属性值,属性2:属性值...})
- 以上为创建新节点的基本格式,标签可以有多个
- 可以同时创建多个节点,多个以逗号隔开
创建关系
方式一
- 在创建节点同时创建关系
create (one:Person{name: "成龙"}),
(two:Person{name: "李连杰"}),
(three:Person{name: "周润发"}),
(four:Person{name: "郭富城"}),
(five:Person{name: "张学友"}),
(one)-[:knows]->(three),
(one)-[:blocks]->(two);
方式二
- 在已有的节点上创建关系
create (one:Person{name: "one"}),
(two:Person{name: "two"});
- 现有两个节点,one和two,首先查询出a,b两个节点
- 对a、b节点执行创建关系语句,同时也可以返回或不返回节点
- 多次提交则会创建多个关系
match (a:Person),(b:Person)
where a.name="one" and b.name="two"
create (a)-[:关系1{name:"关系"}]->(b)
return a,b;
Parameter
- 在浏览器使用
:param
定义临时变量,在创建节点时,使用$引用节点
:param { "props" : { "name" : "Andy", "position" : "Developer" } }
CREATE (n:Person $props)
RETURN n
delete
- 用于删除节点、关系或路径,而标签和属性的删除,使用remove命令
create (a:Person{name:'a', age: 36}),
(b:Person{name:'b', age: 25}),
(c:Person{name:'c', age: 26}),
(d:Person{name:'d'}),
(a)-[:knows]->(b),
(a)-[:knows]->(c);
删除一个节点
- 首先查找到对应的节点,然后使用delete删除,可以选择返回或不返回删除的节点
- 因此删除节点有多个写法,可以使用match匹配,也可以使用where语句进行匹配
match (n:Person{name:'d'})
delete n
return n;
match(n:Person) where n.name='d'
delete n return n;
删除节点和关系
- 删除所有的节点和关系,这种方式不适用于删除大量数据
match(n) detach delete n;
- 同理,如果只想要删除某个节点和这个节点下的关系,则只需要进行查询即可
- 和这个节点相关的关系都会被删除
match(n {name:'a'}) detach delete n;
仅仅删除关系
MATCH (n {name: 'b'})-[r:knows]->()
detach DELETE r
- 删除属性name为b的节点发出的关系,不会对其他节点发出的关系有影响
- 同时,使用detach与不使用效果相同
set
为属性设置属性值
首先查询到要修改的节点,使用set对节点进行设置
这里需要注意,如果用where,则set在where之后
支持在浏览器中使用
:param
定义json变量,使用$
替换变量形式设置设置属性三种方式:
- 使用逗号隔开
- 使用{}设置所有属性,例如:
set n={name:'111', age:20}
- 使用+追加属性,例如:
set n+={name:'111', age:20}
match(n:Person) where n.name = 'a'
set n.name = 'aa' return n;
MATCH(n:Person{name:'aa'})
set n.name = 'aaa'
return n;
使用复杂表达式
- 在set中可以使用case when等复杂操作
- 利用此特性,可以转换属性的类型,例如int转str,
set n.age = toString(n.age)
MATCH (n {name: 'Andy'})
SET (CASE WHEN n.age = 55 THEN n END).worksIn = 'Malmo'
RETURN n.name, n.worksIn
移除一个属性
- 移除属性,只需将属性值设置为null即可
- 可以使用{}移除所有的属性
设置标签
- 支持设置多个标签
MATCH (n {name: 'a'})
SET n:label1:label2
RETURN n.name, labels(n) AS labels
remove
- remove用于移除label和property
- delete用于删除节点和关系
- 移除节点为
remove n.property
,多个以逗号隔开- 移除标签为
remove n:label:label
MATCH(n:Person {name: 'd'})
remove n.age
return n.age, n.name, n.addr;
遍历语句
foreach
- 使用foreach可以对数据进行遍历
MATCH p=(start)-[*]->(finish)
WHERE start.name = 'A' AND finish.name = 'D'
FOREACH (n IN nodes(p) | SET n.marked = true)
Merge
CREATE (a:Person {name: 'a', addr: 'a'}),
(b:Person {name: 'b', addr: 'a'}),
(c:Person {name: 'c', addr: 'c'}),
(d:Person {name: 'd', addr: 'd'}),
(e:Person {name: 'e', addr: 'a'}),
(f:Movie {name: 'f'}),
(g:Movie {name: 'g'}),
(a)-[:acted_in]->(f),
(a)-[:father]->(d),
(b)-[:acted_in]->(f),
(c)-[:acted_in]->(f),
(c)-[:acted_in]->(g),
(d)-[:acted_in]->(f),
(d)-[:acted_in]->(g),
(e)-[:acted_in]->(g);
- Merge用于确保图形存在模式,要么已经存在要么进行创建
合并节点
- 使用merge,如果节点不存在,则创建一个新的节点,类似于match,只不过match如果查询结果为空,则返回空,而merge则会创建一个新的节点
- 不能使用where语句
merge (a:label1:lable2{属性1:属性值,属性2:属性值})
提取共同属性为新节点
- Person中都有共同的属性addr,如果要将提取出所有的addr,则可以使用下列命令
MATCH (person:Person)
MERGE (city:City {name: person.addr})
RETURN person.name, person.addr, city
On Create
- 如果需要创建,则设置属性;如果节点已经存在,则不进行任何操作
- 支持设置多个属性,以逗号隔开
- 下述命令,如果k不存在,则创建并设置创建时间戳
merge(a:Person{name:'k'}) on create set a.createtime=timestamp() return a.name, a.createtime
On Match
- 与On create相对应,on match是如果节点不存在,则只创建节点;如果已经存在,则设置属性;
- 支持设置多个属性,以逗号隔开
- 下述命令,如果l不存在,则创建l;如果已经存在,则设置updatetime属性
merge(l:Person{name:'l'}) on match set a.updatetime=timestamp() return l
on create和on match同时使用
- on create和on match结合,可实现当节点不能在,则创建节点并设置创建时间;如果存在,则设置更新时间
- 支持设置多个属性,以逗号隔开
merge(l:Person{name: 'l'}) on create set l.createtime =timestamp() on match set l.updatetime=timestamp() return l
作用于relationship
- 匹配两个节点,如果关系不存在,则创建关系,这里的关系匹配包括属性匹配,如果属性不匹配,也会创建一个新的关系
match(k:Person), (l:Person) where k.name='k' and l.name='l' merge (k) -[r:father{name:"父子"}]->(l) return k, type(r), l
匹配多个关系
match(k:Person), (l:Person) where k.name='k' and l.name='l' merge (k)-[r:father{name:"父子"}]->(a:Person{name:'a'})<-[:firend]-(l) return k, type(r), l
关系随机方向
- 没有指定具体方向,则方向随机
MATCH
(charlie:Person {name: 'Charlie Sheen'}),
(oliver:Person {name: 'Oliver Stone'})
MERGE (charlie)-[r:KNOWS]-(oliver)
RETURN r
call
create
(a:Person:Child{name:'Alice', age: 20}),
(b:Person{name:'Dora', age: 30}),
(c:Person:Parent{name:'Charlie', age: 65}),
(d:Person:Child{name:'Bob', age: 27}),
(a)-[:Child_of]->(c),
(a)-[:Friend_of]->(d);
- call允许进行子查询
- 下述例子,首先将[0,1,2,3]转换为4列,对四列数据进行乘以10的操作,注意with必须写,否则找不到x
unwind[0,1,2,3] as x
call {with x return x * 10 as y}
return x, y
结合union
- 找出年龄最小和最大的节点
call{
match(p:Person) return p order by p.age desc limit 1
union
match(p:Person) return p order by p.asc limit 1
}
return p.name,p.age order by p.name
调用函数
java
Neo4j-OGM
- 官方文档:neo4j.com/docs/ogm-ma…
- 对象图谱映射工具,类似与mybatis与hibernate的对象映射工具
知识图谱构建
知识图谱的构建需要经过三个阶段,即
- 知识抽取:通过网络爬虫等结束获得知识图谱的元数据,通过一些技术、算法提取出属性、关系和实体信息
- 知识融合:将知识抽取获得的数据通过相似度分析等手段整合成知识图谱的结构
- 知识加工:对数据进行清洗,以保证数据的可靠性