Neo4j实践
关于
是什么
图形数据库管理系统,是一个高性能、面向对象的数据库系统,用于存储、管理和查询大规模的图形数据。它是一个开源的、ACID兼容的数据库,采用了图形模型来表示数据,这使得它在处理复杂的关系数据方面表现出色。Neo4j是目前最受欢迎的图形数据库之一,它可以被用于许多应用程序领域,包括社交网络、推荐系统、网络安全、生物信息学等。它支持多种编程语言和平台,并且具有良好的可扩展性和高可用性。
为什么使用
- 更适合处理复杂关系型数据:Neo4j采用图形模型来表示数据,可以很好地处理复杂的关系型数据。与传统的关系型数据库相比,Neo4j更加灵活和高效。
- 更快的查询速度:Neo4j是一个面向对象的数据库系统,它使用了索引和缓存技术来提高查询性能。在查询图形数据时,Neo4j可以使用遍历算法来优化查询性能,从而实现更快的查询速度。
- 更好的可扩展性:Neo4j可以轻松地扩展到多个节点,可以实现分布式计算,因此可以处理更大的数据集。
- 更适合处理实时数据:Neo4j是一个内存数据库,支持实时数据处理,适用于实时应用程序和实时数据分析。
- 更容易理解和使用:Neo4j使用基于图形模型的查询语言Cypher,这种查询语言与现代应用程序的数据结构更加相似,因此更容易理解和使用。
综上所述,如果你需要处理复杂关系型数据,需要更快的查询速度、更好的可扩展性和实时数据处理能力,Neo4j可能是更好的选择。而如果你需要处理传统的关系型数据,或者需要使用SQL查询语言,那么传统的关系型数据库可能更适合你的需求。
实践
安装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
version: '3'
services:
neo4j:
image: neo4j:4.3.7
volumes:
- $PWD/data:/data #把容器内的数据目录挂载到宿主机的对应目录下
- $PWD/logs:/logs #挂载日志目录
- $PWD/conf:/var/lib/neo4j/conf #挂载配置目录
- $PWD/import:/var/lib/neo4j/import #挂载数据导入目录
- $PWD/plugins:/plugins
environment:
- NEO4J_dbms_memory_heap_maxSize=4G
- NEO4J_AUTH=neo4j/123456 #修改默认用户密码
ports:
- "7474:7474" #映射容器的端口号到宿主机的端口号
- "7687:7687"
restart: always
|
Cypher
简介
用法 |
|
CREATE 创建 |
创建节点,关系和属性 |
MATCH 匹配 |
检索有关节点,关系和属性数据 |
RETURN 返回 |
返回查询结果 |
WHERE 哪里 |
提供条件过滤检索数据 |
DELETE 删除 |
删除节点和关系 |
REMOVE 移除 |
删除节点和关系的属性 |
ORDER BY 以…排序 |
排序检索数据 |
SET |
添加或更新标签 设置属性 |
LOAD
1
2
|
load cv from "file:///xxx.csv" as line
create (:xiyouRelation (from: line[1],relation:line[3],to: line[0]})
|
MATCH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 查询某个标签全部节点
match (n:xiyouRelation) return n
// 查询所有数量
match (n:xiyouRelation) return count(n)
// 条件查询 in,is null
match (n:xiyouRelation {from:"孙悟空"}) return n
match (n:xiyouRelation) where n.from in["孙悟空","猪八戒"] return n
//关系查询 [:西游关系*n] n确定层级 0只返回自己
MATCH (n:person {name:'孙悟空'})-[:西游关系*2]->(b:person) return n,b
MATCH (n:person {name:'孙悟空'})<-[:西游关系*2]-(b:person) return n,b
// 查询其他参数
// ORDER BY
MATCH (n:person {name:'孙悟空'})-[:西游关系*2]->(b:person) return n,b ORDER BY n.name
// LIMIT
MATCH (n:person {name:'孙悟空'})-[:西游关系*2]->(b:person) return n,b LIMIT 10
// SKIP
MATCH (n:person {name:'孙悟空'})-[:西游关系*2]->(b:person) return n,b SKIP 10
|
CREATE
1
2
3
4
5
6
7
8
|
// 创建一个标签为person的节点,节点有一个name属性,属性值为'小红'
create (n:person {name:"小红"}) return n
// 属性设置
match (n:person {name:"小红"}) set n.age=18 return n
// 给某个标签对外的所有关系增加属性
MATCH p=(person {name:'孙悟空'})-[r:西游关系]->() SET r={since:"2017-01-02"} RETURN p;
|
DELETE
1
2
3
4
5
|
// 删除a节点
match (n:person {name:"小红"}) delete n
//删除关系属性
match (n:person {name:'孙悟空'})-[r:西游关系]->(m:person) REMOVE r.since
|
Springboot 集成
springboot版本 3.0.4
-
引入依赖
1
|
implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
|
-
配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
spring:
neo4j:
uri: bolt://localhost:7687
authentication:
username: neo4j
password: 123456
data:
neo4j:
database: neo4j
logging:
level:
org:
springframework:
data:
neo4j: debug
|
-
创建实体
1
2
3
4
5
6
7
8
9
10
|
@Data
@Node("person")
public class Person {
@Id
@GeneratedValue
private Long id;
@Property
private String name;
}
|
-
Repository
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Repository
public interface PersonRepository extends Neo4jRepository<Person, Long> {
/**
* 根据名称查询
* @param name
* @return
*/
Person findByName(String name);
/**
* 创建关系
*
* @param from
* @param relation
* @param to
*/
@Query("MATCH (n:person {name:$from}),(m:person {name:$to}) CREATE (n)-[:西游关系{relation:$relation}]->(m)")
void createRelation(String from, String relation, String to);
}
|
-
测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@Test
public void testFindAll() {
List<Person> all = personRepository.findAll();
for (Person person : all) {
System.out.println(person);
}
}
@Test
public void testFindById() {
Optional<Person> person = personRepository.findById(295L);
person.ifPresent(System.out::println);
}
@Test
public void testDelete() {
personRepository.deleteById(295L);
}
@Test
public void testCreateObject() {
Person person = new Person();
person.setName("牛魔王");
Person save = personRepository.save(person);
System.out.println(save);
}
|
关系
简单关系
在自身中存储
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
@Data
@Node("person")
public class Person {
@Id
@GeneratedValue
private Long id;
@Property
private String name;
@Relationship(type = "师傅")
public Set<Person> masters;
@Relationship(type = "师兄")
public Set<Person> brothers;
//指定师傅关系
public void masters(Person person) {
if (masters == null) {
masters = new HashSet<>();
}
masters.add(person);
}
public void brothers(Person person) {
if (brothers == null) {
brothers = new HashSet<>();
}
brothers.add(person);
}
public String toString() {
return this.name + " 师傅 => "
+ Optional.ofNullable(this.masters).orElse(
Collections.emptySet()).stream().map(
Person::getName).collect(Collectors.toList())
+ " 师兄 => "
+ Optional.ofNullable(this.brothers).orElse(
Collections.emptySet()).stream().map(
Person::getName).collect(Collectors.toList());
}
}
|
test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Test
public void testCreateRelation() {
Person san = new Person();
san.setName("张三");
Person si = new Person();
si.setName("李四");
Person wu = new Person();
wu.setName("王武");
san.masters(si);
san.brothers(wu);
personRepository.save(san);
// 张三 师傅 => [李四] 师兄 => [王武]
Person name = personRepository.findByName("张三");
System.out.println(name);
}
|
复杂关系(关系中有一些其他属性)
创建关系类
@RelationshipProperties : 指定是一个关系类
@TargetNode : 指定关联对象
1
2
3
4
5
6
7
8
9
10
11
12
|
@RelationshipProperties
@Data
public class XiYouRelationPerson {
@RelationshipId
private Long id;
private String relation;
@TargetNode
private Person property;
}
|
使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Data
@Node("person")
public class Person {
@Id
@GeneratedValue
private Long id;
@Property
private String name;
@Relationship(type = "西游关系")
public List<XiYouRelationPerson> xiYouRelationPeople;
}
|