Neo4j入门

目录

Neo4j

Neo4j概述

为什么使用Neo4j

Neo4j部署安装

​编辑Neo4j数据结构

Cypher入门

1.创建数据

2.查询数据

3.关系深度查询(重点)

4.分页查询

5.更新数据

6.删除数据

7.索引


Neo4j

Neo4j概述

Neo4j是用Java实现的开源NoSQL图数据库。从2003年开始开发,2007年正式发布第一版,其源码托管于GitHtb。Neo4j作为图数据库中的代表产品,已经在众多的行业项目中进行了应用,如:网络管理、软件分析、组织和项目管理、社交项目等方面。

Neo4j实现了专业数据库级别的图数据模型的存储,提供了完整的数据库特性,包括ACID事务的支持、集群的支持、备份和故障转移等。

Neo4j提供了申明式的查询语言Cypher,它类似于关系型数据库中的SQL语言,其具有表现力丰富、使用简单、查询效率高、高扩展性等特点。

它存储的数据大致是这样的:

其中,紫色圆圈是【人】数据,橙色圆圈是【电影】数据,表示人与电影之间参演或导演的数据关系。

为什么使用Neo4j

我们最熟悉的就是mysql关系型数据库,采用行-列的模式存数据。那如果我们要存的数据相互之间都存在一种互相联系的关系。如果我们要使用mysql进行存数据,如1->2,2->3,4->5,存入数据库钟,我现在需要判断1是否与5有关系,我就需要获取与1有关系的2,在找与2有关系的数据。可以发现问题,如果数据量十分庞大,且关系十分复杂,使用mysql来获取关系是非常麻烦的。

因此我们要使用neo4j图数据库,直接使用有向图来表示数据,将以上数据存入图数据库钟,我们就可以从1出发最后到达5这个数据。这就是图数据库的优势

综上所述:如果数据与数据之间存在有向联系,那么我们就可以使用图数据库

Neo4j部署安装

Neo4j支持众多平台的部署安装,如:Windows、Mac、Linux等系统。Neo4j是基于Java平台的,所以部署安装前先保证已经安装了Java虚拟机。

在神领物流项目中,我们采用docker的方式进行安装。安装命令如下:

docker run \

-d \

--restart=always \

--name neo4j \

-p 7474:7474 \

-p 7687:7687 \

-v neo4j:/data \

neo4j:4.4.5

7474是web管理工具的端口,7687是neo4j协议端口进行数据通信

输入网址

http://ip:7474/browser/

连接url需要 使用端口7687

初始账号和密码都是neo4j

登录成功

Neo4j数据结构

  • 节点
    • 存储实体数据,在上图中,演员、电影都是节点。
    • 可以理解为关系型数据库中的一行数据
  • 属性
    • 节点和关系都可以有属性,它是由键值对组成的。
    • 节点的属性可以理解为关系型数据库中的字段。
    • 关系中的属性进一步的明确了关系。
  • 关系
    • 存储节点之间的关系。
    • 关系只能有一个类型**(一个箭头只能表示一种关系,不可以表示多重关系)**,必须有开始节点和结束节点以及指向。
    • 关系可以自我循环引用(就是节点自己指向自己,如自己喜欢自己,喜欢是关系),但是两头永远不能为空(关系必须有起点和终点)。
  • 标签
    • 标签是对节点的分类,这样使得构建Neo4j数据模型更加简单。
    • 在上面的电影案例中,Movie、Person就是标签,可以理解为关系型数据库的表,用来表示相同类型的节点,如上图中黄色节点都是电影,这些的节点的标签都是Movie。

总的来说,多种属性组成一个节点,相同类型的节点都有共同的标签,不同的节点之间有着关系。

Cypher入门

Cypher是Neo4j的查询语言,类似与关系型数据库中的SQL,一些关键词来源于SQL,比如:CREATE、WHERE、RETRUN等。

Cypher语句的关键字对大小写不敏感。

1.创建数据

在Neo4j中使用CREATE命令来创建节点、关系、属性数据。语法如下:

//查询所有数据

match (n) return n //n代表一个变量(可以表示节点(节点里有标签,属性),关系),变量没有任何限制,就是所有数据

//删除所有数据

match (n) detach delete n //删除所有数据

match (n) delete n //删除孤立的节点(没有关系的节点)

//创建一个节点数据

create (n:Person {name:'hhh',age:'18'}) //n代表一个指向这个节点的变量,这个节点的标签是Person,属性有name,age

需要查看这个节点的数据时又需要使用

match(n) return n 语句,而且这个语句返回的是所有数据信息,数据量十分庞大时,不适合使用,如果我们想创建节点完成后返回这个节点的数据我们可以使用

create (n:Person {name:'hhh',age:'18'}) return n //创建完成后自动返回这个节点的数据信息
//创建节点与节点之间的关系

create (p1:Person {name:'aaa',age:'10'}) -[r:boyfriend]->(p2:Person {name:'bbb',age:'11'}) return p1,r,p2

这里我们直接创建了两个节点以及他们之间的关系,p1是p2的男朋友,然后使用r变量指向关系,最后把两个节点和关系数据信息返回给我们看。

我们可以自己选择节点显示的属性内容

那如何我又想要创建bbb与aaa的女朋友关系,我们又需要这样写,但是会重复创建节点报错

所以我们可以把所有的语句合并到一起写

create (p1:Person {name:'aaa',age:'10'})

create (p2:Person {name:'bbb',age:'11'})

create (p1)-[:boyfriend]->(p2),

(p1)<-[:girlfriend]-(p2);

2.查询数据

Cypher查询语法如下:

[MATCH WHERE] //条件查询

[WITH [ORDER BY] [SKIP] [LIMIT]] //查询的结果以管道的形式传递给下面的语句,聚合查询必须使用WITH

RETURN [ORDER BY] [SKIP] [LIMIT] //返回、排序、跳过、返回个数

构造数据

CREATE (北京市转运中心:OLT {bid: 8001, name: "北京市转运中心", address: "北京市转运中心", location : point({latitude:39.904179, longitude:116.407387})})
CREATE (上海市转运中心:OLT {bid: 8002, name: "上海市转运中心", address: "上海市转运中心", location : point({latitude:31.230525, longitude:121.473667})})
CREATE (南京市转运中心:OLT {bid: 8003, name: "南京市转运中心", address: "南京市转运中心", location : point({latitude:32.059344, longitude:118.796624})})
CREATE (太原市转运中心:OLT {bid: 8004, name: "太原市转运中心", address: "太原市转运中心", location : point({latitude:37.870451, longitude:112.549656})})
CREATE (郑州市转运中心:OLT {bid: 8005, name: "郑州市转运中心", address: "郑州市转运中心", location : point({latitude:34.745551, longitude:113.624321})})
CREATE
    (北京市转运中心)-[:IN_LINE {cost:10684.9}]->(上海市转运中心),
    (北京市转运中心)<-[:OUT_LINE {cost:10684.9}]-(上海市转运中心),
    (北京市转运中心)-[:IN_LINE {cost:8993.1}]->(南京市转运中心),
    (北京市转运中心)<-[:OUT_LINE {cost:8993.1}]-(南京市转运中心),
    (南京市转运中心)-[:IN_LINE {cost:2699.4}]->(上海市转运中心),
    (南京市转运中心)<-[:OUT_LINE {cost:2699.4}]-(上海市转运中心),
    (太原市转运中心)-[:IN_LINE {cost:3609.7}]->(郑州市转运中心),
    (太原市转运中心)<-[:OUT_LINE {cost:3609.7}]-(郑州市转运中心),
    (郑州市转运中心)-[:IN_LINE {cost:5659.7}]->(南京市转运中心),
    (郑州市转运中心)<-[:OUT_LINE {cost:5659.7}]-(南京市转运中心)
CREATE (昌平区转运中心:TLT {bid: 90001, name: "昌平区转运中心", address: "昌平区转运中心", location : point({latitude:40.220952, longitude:116.231034})})
CREATE (北京市昌平区新龙城:AGENCY {bid: 100260, name: "北京市昌平区新龙城", address: "龙跃苑四区3号楼底商", phone : "010-53049073,010-53576707", location : point({latitude:40.07544443596149, longitude:116.3470535709328})})
CREATE
    (北京市昌平区新龙城)-[:IN_LINE {cost:189.7}]->(昌平区转运中心),
    (北京市昌平区新龙城)<-[:OUT_LINE {cost:189.7}]-(昌平区转运中心)
CREATE (北京市昌平区定泗路:AGENCY {bid: 100280, name: "北京市昌平区定泗路", address: "北七家镇定泗路苍龙街交叉口", phone : "010-86392987", location : point({latitude:40.11765281246394, longitude:116.37212849638287})})
CREATE
    (北京市昌平区定泗路)-[:IN_LINE {cost:166.2}]->(昌平区转运中心),
    (北京市昌平区定泗路)<-[:OUT_LINE {cost:166.2}]-(昌平区转运中心)
CREATE (海淀区转运中心:TLT {bid: 90002, name: "海淀区转运中心", address: "海淀区转运中心", location : point({latitude:39.959893, longitude:116.2977})})
CREATE (北京市海淀区小营:AGENCY {bid: 100347, name: "北京市海淀区小营", address: "北京市昌平区回龙观街道金燕龙大厦停车场", phone : "010-86483817,010-86483817,010-86483817", location : point({latitude:40.06177798692319, longitude:116.32706587559049})})
CREATE
    (北京市海淀区小营)-[:IN_LINE {cost:116.1}]->(海淀区转运中心),
    (北京市海淀区小营)<-[:OUT_LINE {cost:116.1}]-(海淀区转运中心)
CREATE (北京市海淀区万泉河:AGENCY {bid: 100227, name: "北京市海淀区万泉河", address: "北京市海淀区四季青镇杏石口路47号院", phone : "18521852356", location : point({latitude:39.94882822425318, longitude:116.25707017441161})})
CREATE
    (北京市海淀区万泉河)-[:IN_LINE {cost:36.8}]->(海淀区转运中心),
    (北京市海淀区万泉河)<-[:OUT_LINE {cost:36.8}]-(海淀区转运中心)
CREATE
    (昌平区转运中心)-[:IN_LINE {cost:383.3}]->(北京市转运中心),
    (昌平区转运中心)<-[:OUT_LINE {cost:383.3}]-(北京市转运中心),
    (海淀区转运中心)-[:IN_LINE {cost:112.3}]->(北京市转运中心),
    (海淀区转运中心)<-[:OUT_LINE {cost:112.3}]-(北京市转运中心)
CREATE (浦东新区转运中心:TLT {bid: 90003, name: "浦东新区转运中心", address: "浦东新区转运中心", location : point({latitude:31.221461, longitude:121.544346})})
CREATE (上海市浦东新区南汇:AGENCY {bid: 210057, name: "上海市浦东新区南汇", address: "园春路8号", phone : "18821179169", location : point({latitude:31.035240152911637, longitude:121.73459966751048})})
CREATE
    (上海市浦东新区南汇)-[:IN_LINE {cost:275.4}]->(浦东新区转运中心),
    (上海市浦东新区南汇)<-[:OUT_LINE {cost:275.4}]-(浦东新区转运中心)
CREATE (上海市浦东新区周浦:AGENCY {bid: 210127, name: "上海市浦东新区周浦", address: "川周公路3278-8号", phone : "021-68060322", location : point({latitude:31.132409729356993, longitude:121.59815370294322})})
CREATE
    (上海市浦东新区周浦)-[:IN_LINE {cost:111.6}]->(浦东新区转运中心),
    (上海市浦东新区周浦)<-[:OUT_LINE {cost:111.6}]-(浦东新区转运中心)
CREATE (奉贤区转运中心:TLT {bid: 90004, name: "奉贤区转运中心", address: "奉贤区转运中心", location : point({latitude:30.918406, longitude:121.473945})})
CREATE (上海市奉贤区东部:AGENCY {bid: 210017, name: "上海市奉贤区东部", address: "上上海市奉贤区洪庙镇洪兰路351", phone : "021-57171717", location : point({latitude:30.917752751719863, longitude:121.67587819184698})})
CREATE
    (上海市奉贤区东部)-[:IN_LINE {cost:192.9}]->(奉贤区转运中心),
    (上海市奉贤区东部)<-[:OUT_LINE {cost:192.9}]-(奉贤区转运中心)
CREATE (上海市奉贤区青村:AGENCY {bid: 210442, name: "上海市奉贤区青村", address: "姚家村1127号", phone : "021-57566663,021-57566606", location : point({latitude:30.916946897994983, longitude:121.57954144207972})})
CREATE
    (上海市奉贤区青村)-[:IN_LINE {cost:100.9}]->(奉贤区转运中心),
    (上海市奉贤区青村)<-[:OUT_LINE {cost:100.9}]-(奉贤区转运中心)
CREATE
    (浦东新区转运中心)-[:IN_LINE {cost:68.0}]->(上海市转运中心),
    (浦东新区转运中心)<-[:OUT_LINE {cost:68.0}]-(上海市转运中心),
    (奉贤区转运中心)-[:IN_LINE {cost:347.4}]->(上海市转运中心),
    (奉贤区转运中心)<-[:OUT_LINE {cost:347.4}]-(上海市转运中心)
CREATE (玄武区转运中心:TLT {bid: 90004, name: "玄武区转运中心" , location : point({latitude:32.048644, longitude:118.797779})})
CREATE (江苏省南京市玄武区紫金墨香苑:AGENCY {bid: 25073, name: "江苏省南京市玄武区紫金墨香苑", address: "栖霞区燕尧路100号", phone : "025-58765331,025-83241955,025-83241881", location : point({latitude:32.117016089520305, longitude:118.86319310255513})})
CREATE
    (江苏省南京市玄武区紫金墨香苑)-[:IN_LINE {cost:98.0}]->(玄武区转运中心),
    (江苏省南京市玄武区紫金墨香苑)<-[:OUT_LINE {cost:98.0}]-(玄武区转运中心)
CREATE (江苏省南京市玄武区长江路:AGENCY {bid: 25023, name: "江苏省南京市玄武区长江路", address: "观音阁10号", phone : "18521133265,18695799166", location : point({latitude:32.04803554410631, longitude:118.79190455263355})})
CREATE
    (江苏省南京市玄武区长江路)-[:IN_LINE {cost:5.6}]->(玄武区转运中心),
    (江苏省南京市玄武区长江路)<-[:OUT_LINE {cost:5.6}]-(玄武区转运中心)
CREATE
    (玄武区转运中心)-[:IN_LINE {cost:12.0}]->(南京市转运中心),
    (玄武区转运中心)<-[:OUT_LINE {cost:12.0}]-(南京市转运中心)
CREATE (小店区转运中心:TLT {bid: 90005, name: "小店区转运中心" , location : point({latitude:37.736865, longitude:112.565524})})
CREATE (山西省太原市青龙:AGENCY {bid: 351068, name: "山西省太原市青龙", address: "长治路33号经典家园停车场内13号商铺", phone : "0351-2025888", location : point({latitude:37.83589608758359, longitude:112.56059258109424})})
CREATE
    (山西省太原市青龙)-[:IN_LINE {cost:110.3}]->(小店区转运中心),
    (山西省太原市青龙)<-[:OUT_LINE {cost:110.3}]-(小店区转运中心)
CREATE (山西省太原市长风街:AGENCY {bid: 351045, name: "山西省太原市长风街", address: "平阳路104号省农机公司院内", phone : "18636100730", location : point({latitude:37.809964384001226, longitude:112.55299317699505})})
CREATE
    (山西省太原市长风街)-[:IN_LINE {cost:82.1}]->(小店区转运中心),
    (山西省太原市长风街)<-[:OUT_LINE {cost:82.1}]-(小店区转运中心)
CREATE
    (小店区转运中心)-[:IN_LINE {cost:149.4}]->(太原市转运中心),
    (小店区转运中心)<-[:OUT_LINE {cost:149.4}]-(太原市转运中心)
CREATE (中原区转运中心:TLT {bid: 90006, name: "中原区转运中心" , location : point({latitude:34.74828, longitude:113.612966})})
CREATE (河南省郑州市郑上路:AGENCY {bid: 371067, name: "河南省郑州市郑上路", address: "中原西路西四环西北角", phone : "0371-55116757,0371-68014786", location : point({latitude:34.74753024533005, longitude:113.57428550005442})})
CREATE
    (河南省郑州市郑上路)-[:IN_LINE {cost:35.4}]->(中原区转运中心),
    (河南省郑州市郑上路)<-[:OUT_LINE {cost:35.4}]-(中原区转运中心)
CREATE (河南省郑州市颍河路:AGENCY {bid: 371086, name: "河南省郑州市颍河路", address: "航海西路与西三环交叉口向南300米路西中贸商务", phone : "19139415556", location : point({latitude:34.71593280680163, longitude:113.60398506929064})})
CREATE
    (河南省郑州市颍河路)-[:IN_LINE {cost:36.9}]->(中原区转运中心),
    (河南省郑州市颍河路)<-[:OUT_LINE {cost:36.9}]-(中原区转运中心)
CREATE
    (中原区转运中心)-[:IN_LINE {cost:11.5}]->(郑州市转运中心),
    (中原区转运中心)<-[:OUT_LINE {cost:11.5}]-(郑州市转运中心)

//TLT -> Two Level Transport(二级转运中心)

//OLT -> One Level Transport(一级转运中心)

//AGENCY-->网点

示例

MATCH (n) RETURN n //查询所有的数据,数据量大是勿用

MATCH (n:AGENCY) RETURN n //查询所有的网点(AGENCY),通过n变量来代指所有的AGENCY节点类型

MATCH (n:OLT {name: "北京市转运中心"}) -- (m) RETURN n,m //查询所有与"北京市转运中心"有关系的节点,这个关系没有箭头,即不分关系的方向,不论是被指向还是指向

MATCH (n:OLT {name:"北京市转运中心"}) --> (m:OLT) RETURN n,m //查询所有"北京市转运中心"关联的一级转运中心

MATCH (n:OLT {name:"北京市转运中心"}) -[r:IN_LINE]- (m) RETURN n,r,m //可以指定关系标签查询

MATCH p = (n:OLT {name:"北京市转运中心"}) -[r:IN_LINE]-> (m:OLT) RETURN p //将查询赋值给变量p,然后将变量p返回即可

//通过 type()函数查询关系类型

MATCH (n:OLT {name:"北京市转运中心"}) -[r]-> (m:OLT {name:"南京市转运中心"}) RETURN type(r)

3.关系深度查询(重点)

可以指定关系的深度进行查询,语法格式:-[:TYPE*minHops..maxHops]->

六度分隔(Six Degrees of Separation)理论。

1967年,哈佛大学的心理学教授Stanley Milgram(1933~1984)想要描绘一个连结人与社区的人际连系网。做过一次连锁信实验,结果发现了"六度分隔"现象。简单地说:"你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过六个人你就能够认识任何一个陌生人。"

[MATCH WHERE] //条件查询

[WITH [ORDER BY] [SKIP] [LIMIT]] //查询的结果以管道的形式传递给下面的语句,聚合查询必须使用WITH

RETURN [ORDER BY] [SKIP] [LIMIT] //返回、排序、跳过、返回个数
1.比如我们现在想要查询与【北京市转运中心】关系中深度为1~2层关系的节点

match path=(n:OLT {name:'北京市转运中心'}) -[*1..2]-> (m) return path;//使用path变量接收返回的所有结果,最后把path返回给我们查看即可

也可以这样

match (n:OLT {name:'北京市转运中心'}) -[*1..2]-> (m) return *;// 用*代指返回所有路径数据

也可以直接在where语句里指定节点的数据信息

match path=(n:OLT ) -[*1..2]-> (m)

where n.name='北京市转运中心'

return path;

也可以把1省略


2.获取关系中的数据

关系中有cost属性,我们改如何获取,我们可以使用with语句,还有relationships()函数

match paths=(n:OLT) -[*..2]-> (m)

where n.name='北京市转运中心'

with relationships(paths) AS r //使用函数获取所有节点的关系,并返回

return r;

也可以直接返回


3.找到某一个节点到另一个节点的所有路线

设置查询深度最大为6,也可以设置的比6大

MATCH paths = (n:AGENCY) -[*..6]->(m:AGENCY)

WHERE n.name = "北京市昌平区定泗路" AND m.name = "上海市浦东新区南汇"

RETURN paths;

可以发现有两条路线

4.找到两条路线中长度最短的一条

使用shortestPath()函数,shortestPath函数需要直接作用于两个节点之间的路径,而不能作用与中间变量

错误:

正确:

MATCH shortPath = shortestPath((n:AGENCY) -[*..6]->(m:AGENCY)) //在规定节点路径时直接使用函数

WHERE n.name = "北京市昌平区定泗路" AND m.name = "上海市浦东新区南汇"

RETURN shortPath;

5.查询两个网点之间所有的路线中成本最低的路线,最大深度为10(如果成本相同,转运节点最少)

UNWIND是将列表数据展开操作

//sum()是聚合统计函数,类似还有:avg()、max()、min()等

match paths= (n:AGENCY) -[*..7]->(m:AGENCY) //规定路线,最大深度为7

WHERE n.name = "北京市昌平区定泗路" AND m.name = "上海市浦东新区南汇"

unwind relationships(paths) AS r //将所有的路线的关系展开成多行数据,每一行有cost属性,方便后续的聚合运算(通过列来计算)

with sum(r.cost) AS sumCost,paths // 使用聚合函数求和,并把paths所有路径信息向下传递

return paths order by sumCost ASC,LENGTH(paths) ASC LIMIT 1; //返回的所有路径通过cost总和升序排序,如果一致,再按路径长度升序排序,最后返回一条数据。

4.分页查询

通过bid(唯一值)来进行排序

//分页查询网点,按照bid正序排序,每页查询2条数据,第一页

MATCH (n:AGENCY)

RETURN n ORDER BY n.bid ASC SKIP 0 LIMIT 2

//第二页

MATCH (n:AGENCY)

RETURN n ORDER BY n.bid ASC SKIP 2 LIMIT 2

5.更新数据

更新数据是使用SET语句进行标签、属性的更新。SET操作是幂等性的。
// 更新/设置 属性

MATCH (n:AGENCY {name:"北京市昌平区新龙城"})

SET n.address = "龙跃苑四区3号楼底商101号"

RETURN n

//通过remove移除属性

MATCH (n:AGENCY {name:"北京市昌平区新龙城"}) REMOVE n.address RETURN n

//没有address属性的增加属性

MATCH (n:AGENCY) WHERE n.address IS NULL SET n.address = "暂无地址" RETURN n

6.删除数据

删除数据通过DELETE、DETACH DELETE完成。其中DELETE不能删除有关系的节点,删除关系就需要DETACH DELETE了。

//删除节点

MATCH (n:AGENCY {name:"航头营业部"}) DELETE n
//有关系的节点是不能直接删除的,只能删除孤立节点

MATCH (n:AGENCY {name:"北京市昌平区新龙城"}) DELETE n

//删除节点和这个节点所有的有关关系

MATCH (n:AGENCY {name:"北京市昌平区新龙城"}) DETACH DELETE n

//删除所有节点和关系,慎用!

MATCH (n) DETACH DELETE n

7.索引

在Neo4j中同样也支持索引,对字段做索引可以提升查询速度。

//创建索引语法:

//OPTIONS子句指定索引提供程序和配置。

CREATE [TEXT] INDEX [index_name] [IF NOT EXISTS]

FOR (n:LabelName)

ON (n.propertyName)

[OPTIONS "{" option: value[, ...] "}"]

//示例:

在所有的网点节点的bid属性中增加TEXT文本类型的agency_index_bid索引

CREATE TEXT INDEX agency_index_bid IF NOT EXISTS FOR (n:AGENCY) ON (n.bid)

//删除索引语法:

DROP INDEX index_name

//示例:

DROP INDEX agency_index_bid

相关推荐
知初~23 分钟前
出行项目案例
hive·hadoop·redis·sql·mysql·spark·database
山猪打不过家猪1 小时前
ASP.NET Core Clean Architecture
java·数据库·asp.net
qwy7152292581632 小时前
13-R数据重塑
服务器·数据库·r语言
Bio Coder2 小时前
R语言安装生物信息数据库包
开发语言·数据库·r语言
钊兵3 小时前
数据库驱动免费下载(Oracle、Mysql、达梦、Postgresql)
数据库·mysql·postgresql·oracle·达梦·驱动
weixin_425878234 小时前
Redis复制性能优化利器:深入解析replica-lazy-flush参数
数据库·redis·性能优化
左灯右行的爱情4 小时前
Redis数据结构总结-listPack
数据结构·数据库·redis
隔壁老王1565 小时前
mysql实时同步到es
数据库·mysql·elasticsearch
想要打 Acm 的小周同学呀5 小时前
Redis三剑客解决方案
数据库·redis·缓存