Neo4j
一、什么是neo4j?
Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。Neo4j也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。程序员工作在一个面向对象的、灵活的网络结构下而不是严格、静态的表中——但是他们可以享受到具备完全的事务特性、企业级的数据库的所有好处。
简单来说:就是一个知识图谱,存放相互关系的数据库。
二、Neo4j的结构及用法
Neo4j中不存在表的概念,只有两类:节点(Node)和关联(Relation),可以简单理解为图里面的点和边。
在数据查询中,节点一般用小括号(),关联用中括号[]。
当然也隐含路径的概念,是用节点和关联表示的,如:(a)-[r]->(b),表示一条从节点a经关联r到节点b的路径。
节点和节点之间是有指向的,可以是单向的也可以是双向的,因为我们在删除某一个节点node的时候,需要先删除他们之间的关系再删除节点。
三、Neo4j Cypher语句的用法
Noe4j采用的是cql语法,跟我们平常接触的语法是不一样的,有点类似hbase的语法操作。
具体介绍如下:
创建节点:
create (n:people{name:'小伟',age:'26',sex:'男'}) return n;
这里我们可以看到我们创建了一个node,这node有3个属性name,age,sex,一个标签,标签为people,return表示返回,不添加不返回,n是变量;
[图片上传失败...(image-5fd94-1538961427110)]
再创建一个node用于后面添加关系
create (n:people{name:'小红',age:'22',sex:'女'}) return n;
创建关系:
创建小伟和小红之间的关系
match (a),(b) where a.name='小伟' and b.name='小红' create (a)-[f:friend{date:'201809'}]->(b);
可以看到,我们建立了小伟和小红之间的关系
语法为:match (xx),(xxx) where xxxx create (xx)-[x:xx{}]->(xxx)
也可以采用这样的方法:
start a =node(0),b=node(1) create (a)-[f:friend]->(b)return n
(小伟是小红的朋友):小伟节点id为0,小红节点id为1
[图片上传失败...(image-d8afb5-1538961427110)]
删除节点:
match (n:people{name:'小伟'}) delete n;
我们可以看到我们在删除节点的时候会报错提示删除节点必须先删除关系
[图片上传失败...(image-ea3414-1538961427110)]
那么我们先删除关系
match (:people{name:'小伟'})-[r:friend]->(:people{name:'小红'}) delete r;
我们可以看到删除了2个关系
[图片上传失败...(image-8b7282-1538961427110)]
然后我们再来删除小红和小伟这2个node
可以看到我们都可以是删除了:
[图片上传失败...(image-244b80-1538961427110)]
查询数据:知识图谱有数据类型,age='18'和age=18是不相同的
match (n:people) where n.name='小伟' return n;
n表示变量,返回n就是返回一个这个node的全部属性
[图片上传失败...(image-ab5943-1538961427110)]
match (n:people) where n.name='小伟' return n.name,n.sex;
[图片上传失败...(image-5ff8d5-1538961427110)]
neo4j> match (n:people) where n.age=18 return n;
0 rows available after 25 ms, consumed after another 0 ms
neo4j> match (n:people) where n.age='18' return n;
+---------------------------------------------+
| n |
+---------------------------------------------+
| (:people {name: "小明", age: "18", sex: "男"}) |
| (:people {name: "刘森", age: "18", sex: "男"}) |
+---------------------------------------------+
2 rows available after 1 ms, consumed after another 1 ms
Neo4j里面也是有字段类型的,跟java中的一致,表现形式不一样,后面会讲到。
start:开始节点,一般用于有索引的节点或者关联
start n=node(2) return n;
[图片上传失败...(image-57c403-1538961427110)]
start n=node(*) return n;
表示查询所有的,n是变量,是表示第几个node
start开头的查询都是跟索引有关的。
查询关系:
查询小伟和小红之间的关系:
match (:people{name:'小伟'})-[w:workmate]->(:people{name:'小红'}) return w;
[图片上传失败...(image-e8a4ac-1538961427110)]
下面我们介绍多层关系:
我们先创建4个node
create (p:people{name:'小飞',age:22,sex:'男'});
create (p:people{name:'小丽',age:20,sex:'女'});
create (p:people{name:'小伟',age:25,sex:'男'});
create (p:people{name:'小猪',age:21,sex:'女'});
neo4j> start a=node(*) return a;
+-------------------------------------------+
| a |
+-------------------------------------------+
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小伟", age: 25, sex: "男"}) |
| (:people {name: "小飞", age: 22, sex: "男"}) |
+-------------------------------------------+
给他们之间建立关系,小飞送礼物给小丽,小伟也送礼物给小丽,同时送礼物给了小猪
match (a),(b) where a.name='小伟' and b.name='小丽' create (a)-[g:gf{date:'20180920'}]->(b);
match (a),(b) where a.name='小飞' and b.name='小丽' create (a)-[g:gf{date:'20180920'}]->(b);
match (a),(b) where a.name='小伟' and b.name='小猪' create (a)-[g:gf{date:'20180707'}]->(b);
查询小飞送了谁礼物
match (n:people)-[:gf]->(end:people) where n.name='小飞' return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小丽", age: 20, sex: "女"}) |
+-------------------------------------------+
查询哪些是小伟送了谁礼物
match (p:people)-[:gf]->(end:people) where p.name='小伟' return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小猪", age: 21, sex: "女"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
+-------------------------------------------+
也可以这样写:
match (p:people{name:'小伟'})-[:gf]->(end:people) return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小猪", age: 21, sex: "女"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
+-------------------------------------------+
查询哪些人送了礼物给小丽,查询哪些人送了礼物给小猪
match (p:people{name:'小丽'})<-[f:gf]-(start:people) return start;
+-------------------------------------------+
| start |
+-------------------------------------------+
| (:people {name: "小飞", age: 22, sex: "男"}) |
| (:people {name: "小伟", age: 25, sex: "男"}) |
+-------------------------------------------+
match (p:people)<-[:gf]-(start:people) where p.name='小猪' return start;
+-------------------------------------------+
| start |
+-------------------------------------------+
| (:people {name: "小伟", age: 25, sex: "男"}) |
+-------------------------------------------+
无向查询:
查询和小伟,和小飞有礼物往来的人
match (n:people)-[f:gf]-(end:people) where n.name='小伟' return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小猪", age: 21, sex: "女"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
+-------------------------------------------+
match (p:people{name:'小飞'})-[:gf]-(end:people) return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小丽", age: 20, sex: "女"}) |
+-------------------------------------------+
id查询
在neo4j中,每一个节点,会自动有一个唯一Id。
查找id为1的节点,有两种方式:
start n=node(1) return n;
match (n:people) where id(n)=1 return n;
+-------------------------------------------+
| n |
+-------------------------------------------+
| (:people {name: "小丽", age: 20, sex: "女"}) |
+-------------------------------------------+
级次查询(树形遍历)
[图片上传失败...(image-c6c4ba-1538961427109)]
以根部小明为条件,查询第一层,第二层,第三层
match (start:people{name:'小明'})-[:gf*1..1]->(end:people) return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小飞", age: 22, sex: "男"}) |
| (:people {name: "小伟", age: 25, sex: "男"}) |
+-------------------------------------------+
match (start:people)-[:gf*2..2]->(end:people) where start.name='小明' return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小红", age: 20, sex: "女"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小猪", age: 21, sex: "女"}) |
+-------------------------------------------+
查询第三层节点:
match (start:people{name:'小明'})-[:gf*3..3]->(end:people) return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小波", age: 32, sex: "男"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小曼", age: 28, sex: "女"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小张", age: 30, sex: "男"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
+-------------------------------------------+
查询第一层,第二层节点:
match (start:people{name:'小明'})-[:gf*1..2]->(end:people) return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小飞", age: 22, sex: "男"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小红", age: 20, sex: "女"}) |
| (:people {name: "小伟", age: 25, sex: "男"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小猪", age: 21, sex: "女"}) |
+-------------------------------------------+
查询第一层,第二层,第三层节点:
match (start:people{name:'小明'})-[:gf*1..3]->(end:people) return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小飞", age: 22, sex: "男"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小红", age: 20, sex: "女"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小曼", age: 28, sex: "女"}) |
| (:people {name: "小伟", age: 25, sex: "男"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小猪", age: 21, sex: "女"}) |
| (:people {name: "小张", age: 30, sex: "男"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
+-------------------------------------------+
查询第二层,第三层:
match (start:people{name:'小明'})-[:gf*2..3]->(end:people) return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小红", age: 20, sex: "女"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小曼", age: 28, sex: "女"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小猪", age: 21, sex: "女"}) |
| (:people {name: "小张", age: 30, sex: "男"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
+-------------------------------------------+
以根部为条件,按级次查询出所有直接或间接获得过小明的礼物的人
match (start:people{name:'小明'})-[:gf*]->(end:people) return end;
+-------------------------------------------+
| end |
+-------------------------------------------+
| (:people {name: "小飞", age: 22, sex: "男"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小红", age: 20, sex: "女"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小曼", age: 28, sex: "女"}) |
| (:people {name: "小伟", age: 25, sex: "男"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小猪", age: 21, sex: "女"}) |
| (:people {name: "小张", age: 30, sex: "男"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
+-------------------------------------------+
Delete:删除节点
删除点要先删除节点之间的关系
删除2个节点之间的关系:如删除啊小猪和小张之间的关系
match (a:people{name:'小猪'})-[g:gf]->(b:people{name:'小张'}) delete g;
再次查看小猪送礼物的人
match (p:people)-[:gf]->(o:people) where p.name='小猪' return p;
+-------------------------------------------+
| o |
+-------------------------------------------+
| (:people {name: "小波", age: 32, sex: "男"}) |
+-------------------------------------------+
查看谁送礼物给了小猪
match (p:people{name:'小猪'})<-[:gf]-(o:people) return o;
+-------------------------------------------+
| o |
+-------------------------------------------+
| (:people {name: "小伟", age: 25, sex: "男"}) |
+-------------------------------------------+
再次查看与小猪礼物往来的人
match (p:people)-[:gf]-(o:people) where p.name='小猪' return o;
+-------------------------------------------+
| o |
+-------------------------------------------+
| (:people {name: "小波", age: 32, sex: "男"}) |
| (:people {name: "小伟", age: 25, sex: "男"}) |
+-------------------------------------------+
我如上可以看到,小猪与小张之间的关系删除了,那么我要先查看小张与其他人是否存在关系
match (p:people)-[:gf]-(o:people) where p.name='小张' return o;
0 rows available after 24 ms, consumed after another 2 ms
说明小张没有任务关系存在了,那么可以删除了。
match (p:people{name:'小张'}) delete p;
0 rows available after 34 ms, consumed after another 0 ms
Deleted 1 nodes
Count
(不按属性)查询标签(people)中一共有多少节点(人):
match (p:people) return count(p);
+----------+
| count(p) |
+----------+
| 9 |
+----------+
也可以起一个别名
match (p:people) return count(p) as counts;
+--------+
| counts |
+--------+
| 9 |
+--------+
(按属性)查询标签(people)中年龄为20岁的一共有多少节点(人):
match (p:people) where p.age=20 return count(p);
match (p:people{age:20}) return count(p);
+----------+
| count(p) |
+----------+
| 2 |
+----------+
以上2种写法都是可以的。
Limit
查询标签(people)中的5个节点(人):
match (p:people) return p limit 5;
+-------------------------------------------+
| p |
+-------------------------------------------+
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:people {name: "小伟", age: 25, sex: "男"}) |
| (:people {name: "小猪", age: 21, sex: "女"}) |
| (:people {name: "小明", age: 30, sex: "男"}) |
| (:people {name: "小红", age: 20, sex: "女"}) |
+-------------------------------------------+
Distinct
查询标签(people)中所有的不同的age,对具体某一个属性去重。
match (p:people) return distinct(p.age);
+---------+
| (p.age) |
+---------+
| 20 |
| 25 |
| 21 |
| 30 |
| 22 |
| 32 |
| 34 |
| 28 |
+---------+
Order by
根据标签(people)中的name 排序:
match (p:people) return p order by p.name;(默认升序)
match (p:people) return p order by p.name desc;(降序)
match (p:people) return p order by p.name asc;(升序)
+-------------------------------------------+
| p |
+-------------------------------------------+
| (:people {name: "小飞", age: 22, sex: "男"}) |
| (:people {name: "小红", age: 20, sex: "女"}) |
| (:people {name: "小猪", age: 21, sex: "女"}) |
| (:people {name: "小波", age: 32, sex: "男"}) |
| (:people {name: "小李", age: 34, sex: "男"}) |
| (:people {name: "小曼", age: 28, sex: "女"}) |
| (:people {name: "小明", age: 30, sex: "男"}) |
| (:people {name: "小伟", age: 25, sex: "男"}) |
| (:people {name: "小丽", age: 20, sex: "女"}) |
+-------------------------------------------+
查询id为1,3,4的节点:
match (n) where id(n) in[1,3,4] return n;
+-------------------------------------------+
| (:people {name: "小丽", age: 20, sex: "女"}) |
| (:friend {name: "小张", age: 32, sex: "男"}) |
| (:friend {name: "小猪", age: 21, sex: "女"}) |
+-------------------------------------------+
Exists
判断节点是否存在 name这个属性:
Match (n) where exists(n.name) return n
With
查询name以‘小’开头的节点:
match (n) where n.name starts with '小' return n;
查询name以‘明’结尾的节点:
match (n) where n.name ends with '明' return n;
(:people {name: "小明", age: 30, sex: "男"})
Contains
查询name中含有 ‘峰’的节点
match (n) where n.name contains '峰' return n;
+-------------------------------------------+
| (:friend {name: "小峰", age: 32, sex: "男"}) |
+-------------------------------------------+
删除节点关系的同时删除所有数据:
match (n) detach delete n
或者
MATCH (n)
OPTIONAL MATCH (n)-[r]-()
DELETE n,r
Match 与optional match的对比:
MATCH语句用于指定的模式检索数据库
OPTIONAL MATCH语句用于搜索模式中描述的匹配项,对于找不到的项,用null代替;在Cypher语句中,类似于SQL语句中的outer join
添加索引
为了查询更快,需要添加索引,给每个标签的重要字段添加不能全部添加会报错
CREATE INDEX ON :Product(productID);
Start的使用
按关系查询多个节点:
start a = node(14) match b-[r]<->a return r,b; <->表示双向的,就是查询a到b,b到a的关系
start a = node(0) match c-[:KNOWS]->b-[:KNOWS]->a return a,b,c; //查找两层KNOWS关系的节点
start a = node(21) match b-[]->a return a,b; //表示查找所有与a节点有关系的节点
修改属性值:
start a = node(*) where a.name="a" set a.name="A" return a,a.name ;
start n=node(0) set n.name="Root",n.ID="001" ; //给默认的根节点添加name,ID属性,便于查询。
With用法示例
with从句可以连接多个查询的结果,即将上一个查询的结果用作下一个查询的开始。
两种用法:
1、通过使用oder by 和limit,with可以限制传入下一个match子查询语句的实体数目。
2、对聚合值过滤。
match (p:person{name:'xiaowei'})-[:gf]-(o) return o;无向查询所有与xiaowei与礼物关联的人
match (p:person{name:'xiaowei'})-[:gf]-(o) with o,count(o) as counts where counts=1 return o,counts;
(1)match与”xiaowei”关联(无向)的o;(2)然后return出等于1的o。
MATCH (n) WITH n ORDER BY n.name DESC LIMIT 3 RETURN collect(n.name)
(1)match所有人;(2)对所有人的name进行降序排列,并取top-6;(3)返回top-6的name并组成collect:返回结果为:["lisi", "name", "wangwu", "xiaofei", "xiaowei", "zhangsan"] collect是一个集合
在路径搜索的时候限制分支数:如下2种写法都是可以的
match (p:person{name:'xiaowei'})-[:gf]-(o) with o order by o.name desc limit 1 match (o)--(n) return n;
match (p:person{name:'xiaowei'})--(o) with o order by o.name desc limit 1 match (o)--(n) return n;
(1)从”xiaowei”出发,找到关联(无向)的所有人的集合o;(2)对集合o按照name降序排列,取top-1;(3)返回与top-1关联(无向)的所有人。
Neo4j复杂查询Unwind:
拆解collect:
UNWIND[1,2,3] ASx RETURN x 结果为1,2,3
collect去重:
WITH [1,1,2,2] AScoll UNWIND coll ASx WITH DISTINCTx RETURNcollect(x) AS SET
利用collection的参数创建nodes
{ "events" : [ { "year" : 2014, "id" : 1}, { "year" : 2014, "id" : 2} ] }
查询语句
UNWIND { events } AS event MERGE (y:Year{ year:event.year}) MERGE (y)<-[:IN]-(e:Event { id:event.id }) RETURN e.id ASx ORDER BY x
Neo4j CQL已提供SET子句来执行以下操作。
向现有节点或关系添加新属性
添加或更新属性值
四、数据导入
Neo4j数据的导入有如下几种方式:
[图片上传失败...(image-b6f24c-1538961427102)]
官方实际例子:
LOAD CSV FROM "http://data.neo4j.com/examples/person.csv" AS line
fieldterminator '\t'
MERGE (n:Person {id: toInt(line[0])})
SET n.name = line[1]
RETURN n
第一种方式:采用load 形式导入csv:此种方式只适合小批量的导入,1000nodes每秒
新建一个csv文件,格式如下,必须是逗号分隔
person_Format.csv
id,name,age
1,zhangsan,18
2,lisi,28
3,wangwu,60
4,xiaofei,25
5,xiaowei,26
load csv from "file:/root/person_Format.csv" as line return count(*);
会提示报错:
Couldn't load the external resource at: file:/root/neo4j/import/root/person_Format.csv
必须将csv文件放入到/root/neo4j/import就是neo4j的安装目录的import目录下
USING PERIODIC COMMIT 300 使用自动提交,每满300条提交一次,防止内存溢出
load csv from "file:/person_Format.csv" as line MERGE (p:person{id:line[0],name:line[1],age:line[2]});
为什么采用merge而不采用create了,因为merge可以去重,避免重复。
neo4j> start n=node(*) return n;
+--------------------------------------------------+
| n |
+--------------------------------------------------+
| (:person {name: "name", id: "id", age: "age"}) |
| (:person {name: "xiaofei", id: "4", age: "25"}) |
| (:person {name: "xiaowei", id: "5", age: "26"}) |
| (:person {name: "lisi", id: "2", age: "28"}) |
| (:person {name: "zhangsan", id: "1", age: "18"}) |
| (:person {name: "wangwu", id: "3", age: "60"}) |
+--------------------------------------------------+
继续导入数据的同时添加关系:
USING PERIODIC COMMIT 100
LOAD CSV FROM “file:///roles.csv” AS line
MATCH (from:movies{movieId:line[2]}),(to:actors{personId:line[0]})
merge (from)-[r:ACTED_IN{miles:line[1]}]-> (to)
return r
我们使用Neo4j CQL SET子句向现有节点或关系添加新属性。
我们使用Neo4j CQL REMOVE子句来删除节点或关系的现有属性。
Neo4j CQL REMOVE命令用于
删除节点或关系的标签
删除节点或关系的属性
Neo4j CQL DELETE和REMOVE命令之间的主要区别 -
DELETE操作用于删除节点和关联关系。
REMOVE操作用于删除标签和属性。
Neo4j CQL DELETE和REMOVE命令之间的相似性 -
这两个命令不应单独使用。
两个命令都应该与MATCH命令一起使用。
neo4j通过skip子句控制返回的数量,skip 2表示跳过前2行
match (cc:CreditCard) return cc skip 2
第二种方式:批量导入
./neo4j-admin load--from={yourpath}/2018-09-18.dump --database=graph.db --force
前提条件是要先停止neo4j服务
五、接口访问
Java api访问
final PropertyUtil property = PropertyUtil.getInstance();
final String url = property.getString("db.jdbc.url", "");
final String username = property.getString("username", "");
final String pwd = property.getString("pwd", "");
Connection conn = null;
Statement stmt = null;
try {
Class.forName("org.neo4j.jdbc.Driver");
conn = DriverManager.getConnection(url, username, pwd);
String sql = "start n=node(*) return n.name,n.age,n.id;";
stmt = conn.createStatement();
final ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getString("n.name"));
}
} catch (Exception e) {
e.printStackTrace();
}
配置文件:
jdbc info
db.jdbc.url=jdbc:neo4j:http://192.168.1.11/7474/
username=neo4j
pwd=123456
所需要的依赖包:
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-jdbc</artifactId>
<version>3.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.neo4j/neo4j-jdbc-driver -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-jdbc-driver</artifactId>
<version>3.4.0</version>
</dependency>
Neo4j java api的实现:
public class Neo4jApi {
// Embedded Neo4j会在本地产生一个文件夹(类似于Mysql的数据库)
private static File storeDir = new File("D://neo4j/");
private static GraphDatabaseService database = null;
/**
* 一个实例对应一个线程,避免线程复用造成错误
*
* @param database
*/
public static void registerShutdownHook(final GraphDatabaseService database) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
database.shutdown();
}
});
}
private static enum RelTypes implements RelationshipType {
RELEASED;
}
/**
* 添加数据
*
* @param database
*/
public static void addData(GraphDatabaseService database) {
Node node1;
Node node2;
Label label1;
Label label2;
Relationship relationship;
Transaction tx = null;
try {
tx = database.beginTx();
//创建标签
label1 = Label.label("Musician");
label2 = Label.label("Album");
//创建节点并设置属性
node1 = database.createNode(label1);
node1.setProperty("name", "jay_chou");
node2 = database.createNode(label2);
node2.setProperty("name", "范特西");
//创建关系及属性
relationship = node1.createRelationshipTo(node2, RelTypes.RELEASED);
relationship.setProperty("date", "2019-09-20");
//打印结果
System.out.println("created node1 name is:" + node1.getProperty("name"));
System.out.println("created relationship is:" + relationship.getProperties("date"));
System.out.println("created node2 name is:" + node1.getProperties("name"));
tx.success();
} catch (Exception e) {
e.printStackTrace();
} finally {
tx.close();
database.shutdown();
}
}
/**
* 查询节点并更新节点
*
* @param database
*/
public static void queryAndUpdate(GraphDatabaseService database) {
Transaction tx = null;
try {
tx = database.beginTx();
final Label label = Label.label("Musician");
//查找数据,需要根据标签,属性查找
final Node node = database.findNode(label, "name", "范特西");
System.out.println("the query node name:" + node.getProperties("name"));
node.setProperty("birthday", "1999-10-01");
System.out.println(node.getProperty("name") + "'s birthday is " + node.getProperty("birthday", new String()));
//提交事务
tx.success();
} catch (Exception e) {
e.printStackTrace();
} finally {
tx.close();
database.shutdown();
}
}
/**
* 删除节点,删除节点之前要删除节点之间的关系
*
* @param database
*/
public static void delete(GraphDatabaseService database) {
Transaction tx = null;
try {
tx = database.beginTx();
final Label label = Label.label("Album");
//获取节点
final Node node = database.findNode(label, "name", "范特西");
//获得关系
final Relationship relationship = node.getSingleRelationship(RelTypes.RELEASED, Direction.INCOMING);
//删除关系
relationship.delete();
//删除节点
relationship.getStartNode().delete();
node.delete();
tx.success();
} catch (Exception e) {
e.printStackTrace();
} finally {
tx.close();
database.shutdown();
}
}
public static void main(String[] args) {
database = new GraphDatabaseFactory().newEmbeddedDatabase(storeDir);
registerShutdownHook(database);
addData(database);
}
}
网友评论