图数据库-Neo4j

文章目录


前言

Neo4j 是一个高性能的 NoSQL 图形数据库系统,它使用图形模型来存储和处理数据。在 Neo4j 中,数据被表示为节点(Nodes)和关系(Relationships),这使得它非常适合用于存储高度互联的数据集。


1.安装

图数据库驱动版本:3.5.31(社区版)
官方下载地址为:https://neo4j.com/download-center/#releases

2.访问neo4j图形化界面

地址:localhost:7474,初次访问账号密码都是neo4j
在这里插入图片描述

3.使用

图数据中只有两种结构。Node节点和Relationship关系
在这里插入图片描述
在neo4j中使用的数据库语言是cypher图形查询语言,类比sql的cql
在这里插入图片描述

4.简单的cql

4.1 创建一个包含属性的节点

Cql:create (n:Building{buildingName:"测试建筑1"})

在这里插入图片描述

4.2 创建一个关系

Cql:create (b1:Building{buildingName:"测试建筑1"})-[:direct]->(b2:Building{buildingName:"测试建筑2"})

在这里插入图片描述

4.3 查看所有节点和关系

Cql:match (n) return n 

在这里插入图片描述

4.4 简单说明

()代表一个节点[]代表一个关系,这两种括号内第一个 : 确定节点类和关系类
例如:(:Building)代表一个Building类的节点,(:Room)代表一个Room类节点,[:direct] 代表一个direct类关系,冒号之前的可以作为当前节点标签或者关系的变量简称
例如:(n:Building) n就可以作为所有Building标签的的简称 [r:direct]是所有direct关系的简称

4.5 查询节点

4.5.1通过标签查询

 查询所有的Building标签的节点 : match (n:Building) return n

在这里插入图片描述

4.5.2 通过id查询

查询指定id的节点:match (n) where id(n)=219302  return n

在这里插入图片描述

4.5.3 查询没有关联关系的节点

查询没有关联关系的节点:MATCH (n) WHERE NOT (n)-–() return n

4.6 更新节点的属性

4.6.1 通过节点id更新节点属性

如果要修改单个节点的属性,推荐使用id或者使用唯一属性作为标识修改属性 使用id:match (n) where id(n)=219301  with n set n.buildingName="修改建筑1"

在这里插入图片描述

4.6.2 更新所有该标签的属性

修改所有该标签且该属性的节点的属性:match (n:Building{buildingName:"测试建筑2"}) with n set n.buildingName = "修改建筑2"

4.7 移除节点

思路是先查出来再删除,但是删除前需要先移除当前节点所有的关联关系

在这里插入图片描述

4.7.1 移除关系

移除所有节点之间的direct关系:match ()-[r:direct]->() with r delete r

在这里插入图片描述

4.7.2 移除没有任何关系的节点(通过唯一标识移除)

可以通过id或唯一标签移除指定节点,或者同一标签的所有节点:match (n) where id(n) = 219302 with n delete n

在这里插入图片描述

4.7.3 移除所有的节点和关系(清空)

删除所有节点和关系:MATCH (r) DETACH DELETE r

4.8 查询路线

先创建一套节点和关系 路线查询

在这里插入图片描述

4.8.1 查询建筑1到所有的Floor标签的路线

在这里插入图片描述
结果集合
在这里插入图片描述

4.8.2 查询建筑1到所有的Room标签所有路线

4.8.2.1 逐层查询路线
查询建筑1到房间标签的所有路径: match p=(b:Building{buildingName:"建筑1"})-[]->(f:Floor)-[]->(r:Room) return p

在这里插入图片描述
结果集合
在这里插入图片描述
如果建筑1到房间标签没有出了楼层Floor以外的其他节点,可以直接使用()代替(f:Floor)

4.8.2.2 省略写法
match p=(b:Building{buildingName:"建筑1"})-[*2]->(r:Room) return p

在这里插入图片描述
查询语句翻译:查询路线p = 第一个节点b是Building标签,属性建筑名为“建筑1”,中间经过任意关系两次[*2](也可以认为深度为2),到达最后一个节点r是Room标签,返回所有路线。

4.8.3 两个节点之间关系

任意两个关系:()-[*2]->()
任意两个以内:()-[*..2]->()
任意两个以上:()-[*2..]->()
任意一个以上两个以内:()-[*1..2]->()

5.进阶的cql

5.1 使用match查询的结果作为条件,进行下一次操作

进行下一次操作包含增删改查,都可以。使用with关键字
match p=(b:Building{buildingName:"建筑1"})-[]->(f:Floor{floorName:"楼层1"}) with f match p=(f)-[]->(r:Room) return p,r

在这里插入图片描述
With之后查询不需要使用逗号隔开再次查询,返回可以是所有出现过的简称
结果集合
在这里插入图片描述

5.2 使用match查询的结果作为条件创建关联关系

match (b1:Building{buildingName:"建筑1"})-[*2]-(r1:Room{roomName:"房间101"})
match (b2:Building{buildingName:"建筑2"})-[*2]-(r2:Room{roomName:"房间101"})
with r1,r2
create (r1)-[:Room2Room]->(r2)
create (r2)-[:Room2Room]->(r1)

在这里插入图片描述
在这里插入图片描述

5.3 查询无方向路线

之前查询路线的时候使用的是()-[]->(),这个是带有方向关系的路线。查询没有方向关系使用的是()-[]-(),但是创建关联关系的时候不能创建无方向的关系。如图5.2(2)中建筑1到建筑2之间的关系是
(b1:Building{buildingName:”建筑1”})-[]->()-[]->(r1:Room)->(r2:Room)<-[]-()<-[]-(b2:Building{buildName:”建筑2”})
查询建筑1到建筑2之间所有的路线

match p=(b1:Building{buildingName:“建筑1”})-[*]-(b2:Building{buildingName:“建筑2”}) return p
在这里插入图片描述
结果集合
在这里插入图片描述

5.4 定向查询

查询有房间关联关系的两栋建筑节点
match (b1)-[]->(f1)-[]->(r1:Room)-[:Room2Room]->(r2:Room)<-[]-(f2)<-[]-(b2:Building) return b1,b2

在这里插入图片描述

6.cql可以返回的结果

6.1 cql返回节点

Match (n:Building) return n

在这里插入图片描述

6.2 cql返回关系

Match (n:Building)-[r:Building2Floor]->() return r

在这里插入图片描述

6.3 cql返回属性

Match (n:Building{buildingId:100000000000}) return n.buildingName

在这里插入图片描述

6.4 cql返回路线

Match p=(n:Building{buildingId:100000000000})-[]->() return p

在这里插入图片描述

6.5 cql返回路线上所有的节点

Match p=(n:Building{buildingId:100000000000})-[]->() return NODES(p)

在这里插入图片描述
一条路线上所有的节点为一个集合体

6.6 cql返回路线长度

Match p=(n:Building{buildingId:100000000000})-[*]->() return Length(p)

在这里插入图片描述

6.7 返回路线上所有节点(去重)

正常执行cql查询所有节点:Match p=(n:Building{buildingId:100000000000})-[*2]->(r1:Room)-[]-(r2:Room) return NODES(p)

在这里插入图片描述
在这里插入图片描述
有两个条结果,因为再room到room之间有两种关系,一个正向的Room2Room一个是反向的Room2Room,
但是这两两条路线上经过的节点都是一样的可以使用distinct去重实现,返回节点集合唯一
Match p=(n:Building{buildingId:100000000000})-[*2]->(r1:Room)-[]-(r2:Room) return distinct NODES§
在这里插入图片描述
在这里插入图片描述

7.将Neo4j集成到Springboot中

集成Neo4j采用的是Spring-data-neo4j。Springboot版本是2.4.0对应Neo4j的driver驱动版本是6.0.1

7.1 导入依赖

Pom:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
这里说明一下,Springboot2.4之前的Spring-data-neo4j的类和2.4之后的类有很大的不同,做了比较大的改动

7.2 配置参数

Application.yml
spring:
  neo4j:
    uri: bolt://localhost:7687
    authentication:
      username: neo4j
      password: 123456
使用bolt协议,也可以使用http协议,端口是7474,但是需要单独引用http驱动包。暂时不做介绍。

7.3 设置节点对象

在这里插入图片描述

7.4 设置关系对象

在这里插入图片描述

7.5 创建持久层

Spring-data-neo4j和Spring-data-jpa类似

7.5.1 节点持久层

在这里插入图片描述
继承Spring-data-neo4j内置的Neo4jRepository可以有很多基础的方法
在这里插入图片描述
也可以通过节点属性来查讯,例如findByBuildName可以直接通过建筑名称查询。

7.5.2 关系持久层

在这里插入图片描述

8.Sprinboot中neo4j的增删改查

8.1添加节点

8.1.1添加单个节点

public void addBuildingNode() {
    Building building = new Building();
    building.setBuildingId(10000L)
            .setBuildingName("Boot添加的一个建筑节点");
    buildingRepository.save(building);
}
执行之后

在这里插入图片描述

8.1.2添加树形结构节点

也可以直接添加树形结构。会自动添加补全关系和节点
例如:
public void addBuildingNode() {
			Building building = new Building();
		 building.setBuildingId(20000L).setBuildingName("测试添加树形节点");
		Floor floor1 = new Floor();
		floor1.setFloorId(21000L).setFloorName("一层");
	    Floor floor2 = new Floor();
		floor2.setFloorId(22000L).setFloorName("二层");
		 List<Floor> floorList = new ArrayList<>();
		floorList.add(floor1);
		floorList.add(floor2);
		building.setFloorList(floorList);
		buildingRepository.save(building);
}

在这里插入图片描述
注:这种结果是建立于创建的对象是有关联关系的。就是有@Relationship注解的,且注解使用正确

8.2移除节点

移除节点和再cql中移除一样,需要保证当前节点没有其他关系之后,才可以直接移除选中的节点。
使用neo4jRepository中自带的delete方法移除节点时,需要保证当前对象有图数据库中的节点id。
public void addBuildingNode() {
    Building building = new Building();
    building.setId(219319L);
    buildingRepository.delete(building);
}

在这里插入图片描述
之前创建的 "Boot添加的一个建筑节点"建筑节点已经被移除

8.3 更新节点

和jpa类似,使用save方法,传入对象的时候带入对象在图数据库中的节点id,就会修改属性。
更新节点也可以修改其	关系下的树形结构。
public void addBuildingNode() {
	    Building building = new Building();
	    building.setId(219339L);
	    building.setBuildingName("更新建筑名称");
	    Floor floor = new Floor();
	    floor.setFloorId(23000L)
	                    .setFloorName("三层");
	    List<Floor> floorList = new ArrayList<>();
	    floorList.add(floor);
	    building.setFloorList(floorList);
	    buildingRepository.save(building);
}

在这里插入图片描述
因为之前添加的楼层Floor节点没有被移除,所以还会存在,但是关联关系已经修改。如果没有传入floorList的集合,就会直接移除所有的floor关系。但是floor节点不会被移除。

8.4 查询节点

8.4.1查询全部

public List<Building> addBuildingNode() {
    List<Building> list = buildingRepository.findAll();
    return list;
}

在这里插入图片描述
在springboot2.4之后,查询全部findAll()方法,不能在指定深度,默认只能再多查到下一层级的接就是Floor节点的数据

8.4.2使用属性查询

public List<Floor> addBuildingNode() {
    List<Floor> list = floorRepository.findByFloorId(23000L);
    return list;
}

在这里插入图片描述
注:能直接查询到指定楼层,但是需要用list集合来接收。
在这里插入图片描述
且查询到的结果层级深度只有当前,不会延伸到下一层

8.5自定义查询

如果需要比较复杂的cql,有两种方法可以使用。
一种是使用@Query注解
一种是使用Neo4jClient

8.5.1使用@Query注解查询

将注解添加到持久层接口的方法上。
该种方法适用于cql比较固定,不会改变的情况。
在使用@Query注解之前要先了解查询结果会对应的类是那些
○返回节点 - 直接使用节点对象集合接收 例如 List<Building>
○返回关系 - 直接使用关系对象接收
○返回属性 - 使用属性对应的数据类型接收
○返回路线 - 使用PathValue接收 例如 List<PathValue> PathValue是Spring-data-neo4j中带的类,用于接收路线对象
○返回路线上的节点集合 - 使用NodeValue接收 例如List<NodeValue> 也是自带的类,用于接收节点对象
○如果是多条路线的节点集合 - 可以使用ListValue接收 例如 List<ListValue> 自带类,可用于接收节点集合
○如果是增删改操作没有返回结果即void

例子:
返回节点
在这里插入图片描述
返回属性
在这里插入图片描述
返回路线
在这里插入图片描述
返回路线上的节点结合
在这里插入图片描述
增删改操作
在这里插入图片描述

8.5.2使用Neo4jClient查询

注入Neo4jClient
直接编写cypher语言,手动执行编写好的cypher语言
该种方法对于可能会频繁变动的cql语句,动态的cql语句支持较好。

@Autowired
private Neo4jClient neo4jClient;
public Collection<Map<String, Object>> addBuildingNode() {
    String cypher = "match (:Building)-[]->(f:Floor) return f";
    Neo4jClient.RunnableSpec query = neo4jClient.query(cypher);
    Collection<Map<String, Object>> all = query.fetch().all();
    all.forEach(map -> {
        map.forEach((k,v) -> {
            Node node = (Node) v;
            System.out.println("节点标签:" + node.labels());
            System.out.println("节点id:" + node.id());
            System.out.println("节点属性:" + node.asMap());
        });
    });
    return all;
}

在这里插入图片描述
使用该种方式查询出来的结果需要自己一步步解析,当前是查询的是节点,使用的是Node
将Object对象转换,对应路线对象也有接收的是PathValue,key值对应的是return返回的内容,例如return f ,map的key值就是 f

9.Neo4j的多数据源事务

import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration
@EnableReactiveNeo4jRepositories
@EnableTransactionManagement
class MyConfiguration {

    public static final String NEO4J_URL = "bolt://localhost/7687";
    public static final String USERNAME = "neo4j";
    public static final String PASSWORD = "123456";
    /**
     * 默认数据库事务
     * @param dataSource
     * @return
     */
    @Bean("transactionManager")
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    // 2. Neo4J的事务管理
    @Bean("neo4jTransactionManager")
    public Neo4jTransactionManager neo4jTransactionManager(Driver driver) {
        return new Neo4jTransactionManager(driver);
    }
    @Bean
    public Driver neo4jDriver() {
        return GraphDatabase.driver(NEO4J_URL, AuthTokens.basic(USERNAME, PASSWORD));
    }
    // 需要使用多种事务时,需要加。
    @Autowired
    @Primary
    @Bean(name = "multiTransactionManager")
    public PlatformTransactionManager multiTransactionManager(
            Neo4jTransactionManager neo4jTransactionManager,
            DataSourceTransactionManager mysqlTransactionManager) {
        return new ChainedTransactionManager(
                neo4jTransactionManager, mysqlTransactionManager);
    }
}

在有图数据和关系型数据库需要一起操作的时候使用multiTransactionManager
使用方式
在这里插入图片描述
如果只涉及到单个数据源就可以使用neo4jTransactionManager或者transactionManager

10.参考网站

Neo4j官网https://neo4j.com/
Spring-data-neo4j-6.0.1Boot官方文档:
https://docs.spring.io/spring-data/neo4j/docs/6.0.1/reference/html/#preface
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值