图数据库Neo4j——SpringBoot使用Neo4j 简单增删改查 复杂查询初步

在这里插入图片描述

前言


图形数据库是专门用于存储图形数据的数据库,它使用图形模型来存储数据,并且支持复杂的图形查询。常见的图形数据库有Neo4j、OrientDB等。

Neo4j是用Java实现的开源NoSQL图数据库,本篇博客介绍如何在SpringBoot中使用Neo4j图数据库,如何进行简单的增删改查,以及如何进行复杂的查询。

本篇博客相关代码的git网址如下:

https://gitee.com/pet365/spring-boot-neo4j

关于Neo4j的博客文章如下:

  • 图数据库Neo4j——Neo4j简介、数据结构 & Docker版本的部署安装 & Cypher语句的入门

目录

  • 前言
  • 引出
  • springBoot整合
    • 1、引入依赖
    • 2、配置文件
    • 3、实体类定义
    • 4、dao继承Neo4jRepository
    • 复杂查询
      • 最短路径查询
      • 最小成本查询
  • 总结

引出


1.Neo4j是用Java实现的开源NoSQL图数据库;
2.SpringBoot使用Neo4j,继承Neo4jRepository进行简单增删改查;
3.使用Neo4jClient进行复杂的查询;

springBoot整合

1、引入依赖

<!--        neo4j的包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-neo4j</artifactId></dependency>

2、配置文件

server:port: 9902
logging:level:org.springframework.data.neo4j: debug
spring:application:name: spring-neo4jdata:neo4j:database: neo4jneo4j:authentication:username: neo4jpassword: neo4j123uri: neo4j://192.168.150.101:7687

3、实体类定义

在这里插入图片描述

提取抽象类

在这里插入图片描述

不同的节点类,网点、一级转运中心、二级转运中心

在这里插入图片描述

4、dao继承Neo4jRepository

进行自定义查询:

KeywordSampleCypher snippet
AfterfindByLaunchDateAfter(Date date)n.launchDate > date
BeforefindByLaunchDateBefore(Date date)n.launchDate < date
Containing (String)findByNameContaining(String namePart)n.name CONTAINS namePart
Containing (Collection)findByEmailAddressesContains(Collection addresses) findByEmailAddressesContains(String address)ANY(collectionFields IN [addresses] WHERE collectionFields in n.emailAddresses) ANY(collectionFields IN address WHERE collectionFields in n.emailAddresses)
InfindByNameIn(Iterable names)n.name IN names
BetweenfindByScoreBetween(double min, double max) findByScoreBetween(Range range)n.score >= min AND n.score <= max Depending on the Range definition n.score >= min AND n.score <= max or n.score > min AND n.score < max
StartingWithfindByNameStartingWith(String nameStart)n.name STARTS WITH nameStart
EndingWithfindByNameEndingWith(String nameEnd)n.name ENDS WITH nameEnd
ExistsfindByNameExists()EXISTS(n.name)
TruefindByActivatedIsTrue()n.activated = true
FalsefindByActivatedIsFalse()NOT(n.activated = true)
IsfindByNameIs(String name)n.name = name
NotNullfindByNameNotNull()NOT(n.name IS NULL)
NullfindByNameNull()n.name IS NULL
GreaterThanfindByScoreGreaterThan(double score)n.score > score
GreaterThanEqualfindByScoreGreaterThanEqual(double score)n.score >= score
LessThanfindByScoreLessThan(double score)n.score < score
LessThanEqualfindByScoreLessThanEqual(double score)n.score <= score
LikefindByNameLike(String name)n.name =~ name
NotLikefindByNameNotLike(String name)NOT(n.name =~ name)
NearfindByLocationNear(Distance distance, Point point)distance( point(n),point({latitude:lat, longitude:lon}) ) < distance
RegexfindByNameRegex(String regex)n.name =~ regex
AndfindByNameAndDescription(String name, String description)n.name = name AND n.description = description
OrfindByNameOrDescription(String name, String description)n.name = name OR n.description = description (Cannot be used to OR nested properties)

在这里插入图片描述

package com.tianju.mapper;import com.tianju.entity.AgencyEntity;
import org.mapstruct.Mapper;
import org.springframework.data.neo4j.repository.Neo4jRepository;/*** 网点的mapper,比如菜鸟驿站*/
@Mapper
public interface AgencyMapper extends Neo4jRepository<AgencyEntity,Long> {/*** 根据bid 查询* @param bid 业务id* @return 网点数据*/AgencyEntity findByBid(Long bid);/*** 根据bid删除** @param bid 业务id* @return 删除的数据条数*/Long deleteByBid(Long bid);
}

在这里插入图片描述

复杂查询

在这里插入图片描述

最短路径查询

//查询两个网点之间最短路径,查询深度最大为10
MATCH path = shortestPath((n:AGENCY) -[*..10]->(m:AGENCY))WHERE n.name = "北京市昌平区定泗路" AND m.name = "上海市浦东新区南汇"RETURN path

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.tianju.mapper.impl;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.meta.Column;
import com.tianju.dto.OrganDTO;
import com.tianju.dto.TransportLineNodeDTO;
import com.tianju.entity.AgencyEntity;
import com.tianju.enums.OrganTypeEnum;
import com.tianju.mapper.TransportLineRepository;
import org.neo4j.driver.internal.InternalPoint2D;
import org.neo4j.driver.types.Path;
import org.neo4j.driver.types.Relationship;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;import java.util.Map;
import java.util.Optional;@Component
public class TransportLineRepositoryImpl implements TransportLineRepository {@Autowiredprivate Neo4jClient neo4jClient;/*** 查询最短路线* @param start 开始网点* @param end   结束网点* @return*/@Overridepublic TransportLineNodeDTO findShortestPath(AgencyEntity start, AgencyEntity end) {// 获取网点数据在Neo4j中的类型 @Node("AGENCY") @Node("OLT")String type = AgencyEntity.class.getAnnotation(Node.class).value()[0];// 构造Sql语句 $startId
//        String cql = "MATCH path = shortestPath((n:AGENCY) -[*..10]->(m:AGENCY))\n" +
//                "WHERE n.bid = $startId AND m.bid = $endId\n" +
//                "RETURN path";String cql = StrUtil.format("MATCH path = shortestPath((n:{}) -[*..10]->(m:{})) " +"WHERE n.bid = $startId AND m.bid = $endId " +"RETURN path",type,type);// 执行自定义查询Neo4jClient.RecordFetchSpec<TransportLineNodeDTO> recordFetchSpec = neo4jClient.query(cql).bind(start.getBid()).to("startId") // 替换 $startId.bind(end.getBid()).to("endId")  // 替换 $endId.fetchAs(TransportLineNodeDTO.class)   // 设置响应类型,指定为 TransportLineNodeDTO 类型.mappedBy((typeSystem, record) -> {    // 设置结果集映射Path path = record.get(0).asPath();// 得到第一条路线TransportLineNodeDTO transportLineNodeDTO = new TransportLineNodeDTO();path.nodes().forEach(node -> { // 将每个节点信息封装成一个 OrganDto// 获得节点的 键值对 address: 上海市转运中心;bid:8002Map<String, Object> map = node.asMap();// {name=北京市昌平区定泗路,// location=Point{srid=4326, x=116.37212849638287, y=40.11765281246394},// address=北七家镇定泗路苍龙街交叉口, bid=100280, phone=010-86392987}System.out.println("map: "+map);// 把键值对转换成对象 OrganDTOOrganDTO organDTO = BeanUtil.toBeanIgnoreError(map, OrganDTO.class);// organDTO:// OrganDTO(id=100280, name=北京市昌平区定泗路, type=null, phone=010-86392987,// address=北七家镇定泗路苍龙街交叉口, latitude=null, longitude=null)// type,latitude,longitude 没有映射成功System.out.println("organDTO: "+organDTO);// 获得标签的名称 OLT,TLT,String first = CollUtil.getFirst(node.labels());// 根据OLT获得枚举类型 OLT(1, "一级转运中心"),OrganTypeEnum organTypeEnum = OrganTypeEnum.valueOf(first);// 再获得枚举类型的 code :1、2、3organDTO.setType(organTypeEnum.getCode()); // 设置类型的映射// 经纬度 "location": point({srid:4326, x:121.59815370294322, y:31.132409729356993})InternalPoint2D location = MapUtil.get(map, "location", InternalPoint2D.class); // 经纬度 BeanUtil.getProperty(map.get("location"),"x");organDTO.setLatitude(location.x());  // 设置经纬度映射organDTO.setLongitude(location.y()); // 经纬度映射// OrganDTO(id=100280, name=北京市昌平区定泗路, type=3,// phone=010-86392987, address=北七家镇定泗路苍龙街交叉口,// latitude=116.37212849638287, longitude=40.11765281246394)System.out.println("organDTO: "+organDTO);transportLineNodeDTO.getNodeList().add(organDTO);});System.out.println("transportLineNodeDTO: "+transportLineNodeDTO);path.relationships().forEach(relationship -> {// 路径下面的关系Map<String, Object> map = relationship.asMap();Double cost = MapUtil.get(map, "cost", Double.class);transportLineNodeDTO.setCost(cost + transportLineNodeDTO.getCost());});System.out.println("transportLineNodeDTO: "+transportLineNodeDTO);return transportLineNodeDTO;});Optional<TransportLineNodeDTO> one = recordFetchSpec.one(); // Optional,1.8提供的,可以处理null的情况return one.orElse(null); // 如果为null,就返回null,如果不是null,就返回结果}
}

最小成本查询

在这里插入图片描述

package com.tianju.mapper.impl;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.meta.Column;
import com.tianju.dto.OrganDTO;
import com.tianju.dto.TransportLineNodeDTO;
import com.tianju.entity.AgencyEntity;
import com.tianju.enums.OrganTypeEnum;
import com.tianju.mapper.TransportLineRepository;
import org.neo4j.driver.internal.InternalPoint2D;
import org.neo4j.driver.types.Path;
import org.neo4j.driver.types.Relationship;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;import java.util.Map;
import java.util.Optional;@Component
public class TransportLineRepositoryImpl implements TransportLineRepository {@Autowiredprivate Neo4jClient neo4jClient;@Overridepublic TransportLineNodeDTO findCostLeastPath(AgencyEntity start, AgencyEntity end) {String type = AgencyEntity.class.getAnnotation(Node.class).value()[0];String cqlB = "MATCH path = (n:{}) -[*..10]->(m:{}) " +"WHERE n.bid = $startId AND m.bid = $endId " +"UNWIND relationships(path) AS r " +"WITH sum(r.cost) AS cost, path " +"RETURN path ORDER BY cost ASC, LENGTH(path) ASC LIMIT 1";String cql = StrUtil.format(cqlB, type,type);Optional<TransportLineNodeDTO> one = neo4jClient.query(cql).bind(start.getBid()).to("startId").bind(end.getBid()).to("endId").fetchAs(TransportLineNodeDTO.class).mappedBy(((typeSystem, record) -> {Path path = record.get(0).asPath();TransportLineNodeDTO transportLineNodeDTO = new TransportLineNodeDTO();path.nodes().forEach(node -> {Map<String, Object> map = node.asMap();OrganDTO organDTO = BeanUtil.toBeanIgnoreError(map, OrganDTO.class);// 获得标签的名称 OLT,TLT,String first = CollUtil.getFirst(node.labels());// 根据OLT获得枚举类型 OLT(1, "一级转运中心"),OrganTypeEnum organTypeEnum = OrganTypeEnum.valueOf(first);// 再获得枚举类型的 code :1、2、3organDTO.setType(organTypeEnum.getCode()); // 设置类型的映射// 经纬度 "location": point({srid:4326, x:121.59815370294322, y:31.132409729356993})InternalPoint2D location = MapUtil.get(map, "location", InternalPoint2D.class); // 经纬度 BeanUtil.getProperty(map.get("location"),"x");organDTO.setLatitude(location.x());  // 设置经纬度映射organDTO.setLongitude(location.y()); // 经纬度映射transportLineNodeDTO.getNodeList().add(organDTO);});path.relationships().forEach(relationship -> {// 路径下面的关系Map<String, Object> map = relationship.asMap();Double cost = MapUtil.get(map, "cost", Double.class);transportLineNodeDTO.setCost(cost + transportLineNodeDTO.getCost());});return transportLineNodeDTO;})).one();return one.orElse(null);}private void findShortestPathMy(){String cql = "MATCH path = shortestPath((n:AGENCY) -[*..10]->(m:AGENCY)) " +"WHERE n.bid = 210127 AND m.bid = 100260 " +"RETURN path";// 执行自定义查询Neo4jClient.UnboundRunnableSpec query = neo4jClient.query(cql);ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();}
}

在这里插入图片描述


总结

1.Neo4j是用Java实现的开源NoSQL图数据库;
2.SpringBoot使用Neo4j,继承Neo4jRepository进行简单增删改查;
3.使用Neo4jClient进行复杂的查询;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/129793.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python连接clickhouse (CK)

Author: tkhywang 2810248865qq.com Date: 2023-11-01 11:28:58 LastEditors: tkhywang 2810248865qq.com LastEditTime: 2023-11-01 11:36:25 FilePath: \PythonProject02\Python读取clickhouse2 数据库数据.py Description: 这是默认设置,请设置customMade, 打开koroFileHead…

【Linux】:Linux开发工具之Linux编辑器vim的使用

&#x1f52b;1.Linux编辑器-vim使用 &#x1f4e4; vi/vim的区别简单点来说&#xff0c;它们都是多模式编辑器&#xff0c;不同的是vim是vi的升级版本&#xff0c;它不仅兼容vi的所有指令&#xff0c;而且还有一些新的特性在里面。例如语法加亮&#xff0c;可视化操作不仅可以…

FPGA_Signal TapII 逻辑分析仪 在线信号波形抓取

FPGA_Signal TapII 逻辑分析仪 在线信号波形抓取 由于一些工程的仿真文件不易产生&#xff0c;所以我们可以利用 quartus 软件自带的 SignalTap 工具对波形进行抓取 对各个信号进行分析处理&#xff0c;让电子器件与FPGA进行正常通讯工作&#xff0c;也验证所绘制的波形图是否一…

【C++】类和对象(中)之拷贝构造与运算符、操作符重载

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 前言 我们继续学习默认成员函数&#xff0c;本篇文…

③ 软件工程CMM、CMMI模型【软考中级-软件设计师 考点】

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ ③ 软件工程CMM、CMMI模型【软考中级-软件设计…

Android 数据恢复的顶级软件分享

人们经常向我们询问有关 Android 数据恢复软件的信息以及它们是否有用。而且&#xff0c;我们给他们讲了两个朋友的故事——凯伦和亚历克斯。他们都丢失了 Android 手机上的一些重要数据。 丢失数据确实是一个令人心碎的时刻&#xff0c;根据丢失的文件&#xff0c;可能会让您…

橙河网络:坏人是怎么形成的?

小A是一个非常热心的人&#xff0c;给谁帮忙&#xff0c;都免费。 大家都说&#xff0c;小 A&#xff0c;实在人呀&#xff0c;哈哈。 小B搬来了&#xff0c;他活多&#xff0c;弄不过来&#xff0c;常找小 A 来帮忙。 小A 每次来帮忙&#xff0c;小B 都给小A一张大团结(100…

oracle (8)Managing Tablespace Data File

目录 一、基础知识 1、表空间和数据文件 2、存储层次结构摘要 3、表空间的类型 4、表空间中的空间管理 5、临时表空间 6、Default Temporary TS 默认临时TS 二、常用实操 1、Creating Tablespaces创建表空间 2、Dictionary-Managed TS 字典管理的表空间 3、Locally …

【idea】生成banner.txt

Spring Boot banner在线生成工具&#xff0c;制作下载英文banner.txt&#xff0c;修改替换banner.txt文字实现自定义&#xff0c;个性化启动banner-bootschool.netSpring Boot banner工具实现在线生成banner&#xff0c;轻松修改替换实现自定义banner&#xff0c;让banner.txt文…

pix2tex - LaTeX OCR 安装使用记录

系列文章目录 文章目录 系列文章目录前言一、安装二、使用三、如果觉得内容不错&#xff0c;请点赞、收藏、关注 前言 项目地址&#xff1a;这儿 一、安装 版本要求 Python: 3.7 PyTorch: >1.7.1 安装&#xff1a;pip install "pix2tex[gui]" 注意&#xff1a…

会声会影2024对比2023变化以及功能对比

全新会声会影2024版本现已登场&#xff0c;小伙伴们相信已经急不可待地想知道2024版到底有哪些新功能。对比2023版本&#xff0c;会声会影2024版本有没有功能的增强&#xff1f;事不宜迟&#xff0c;现在就让我们一起来看看会声会影2024对比2023的变化&#xff0c;包括功能对比…

华为是怎么做全面预算管理的?

大家好&#xff0c;我是老原。 在之前的文章分享中&#xff0c;都穿插着一个很重要但是不被你们重视的的部分&#xff0c;就是预算管理这块。 有很多新手项目经理在做计划的时候&#xff0c;发现自己设备和步骤都不熟悉&#xff0c;根本无从下手&#xff0c;不知道怎么做。 …

XXL-JOB默认accessToken身份绕过RCE漏洞复现 [附POC]

文章目录 XXL-JOB默认accessToken身份绕过RCE漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 XXL-JOB默认accessToken身份绕过RCE漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利用文章内的相关技术从…

Java--网络通信

1.端口Port&#xff1a; 通常计算机上提供了HTTP,FTP等多种服务&#xff0c;客户机通过不同的端口来确定连接到服务器的哪项服务上。 2.套接字Socket&#xff1a; 套接字Socket用于将应用程序与端口连接起来。套接字是一个假想的链接装置。 3.InetAddress类 java.net包中的Ine…

VSCode 如何设置背景图片

VSCode 设置背景图片 1.打开应用商店&#xff0c;搜索 background &#xff0c;选择第一个&#xff0c;点击安装。 2. 安装完成后点击设置&#xff0c;点击扩展设置。 3.点击在 settings.json 中编辑。 4.将原代码注释后&#xff0c;加入以下代码。 // { // "workben…

SpringCloudTencent(上)

SpringCloudTencent 1.PolarisMesh介绍2.北极星具备的功能3.北极星包含的组件4.功能特性1.服务管理1.服务注册2.服务发现3.健康检查 2.配置管理 5.代码实战1.环境准备2.服务注册与发现3.远程调用 1.PolarisMesh介绍 1.北极星是腾讯开源的服务治理平台&#xff0c;致力于解决分…

RESTful接口实现与测试

目录标题 是什么&#xff1f;设计风格HTTP协议四种传参方式常用注解RequestBody与ResponseBodyRequestMapping注解RestController与ControllerPathVariable 与RequestParam 接受复杂嵌套对象参数Http数据转换的原理自定义HttpMessageConverter统一规划接口响应的数据格式实战&a…

【使用Python编写游戏辅助工具】第一篇:概述

引言 欢迎阅读本系列文章&#xff0c;本系列将带领读者朋友们使用Python来实现一个简单而有趣的游戏辅助工具。 写这个系列的缘由源自笔者玩了一款游戏。正巧&#xff0c;笔者对Python编程算是有一定的熟悉&#xff0c;且Python语言具备实现各种有趣功能的能力&#xff0c;因…

MySQL复习总结(一):基础篇

文章目录 一、MySQL概述二、SQL语句2.1 SQL分类2.2 DDL语言2.2.1 数据库操作2.2.2 表操作:通用2.2.3 表操作:修改2.2.4 表操作:删除 2.3 DML语言2.3.1 添加数据2.3.2 修改数据2.3.3 删除数据 2.4 DQL语言2.5 DCL语言 三、函数四、约束五、多表查询5.1 多表关系 六、事务6.1 事务…

Compose-Multiplatform在Android和iOS上的实践

本文字数&#xff1a;4680字 预计阅读时间&#xff1a;30分钟 01 简介 之前我们探讨过KMM&#xff0c;即Kotlin Multiplatform Mobile&#xff0c;是Kotlin发布的移动端跨平台框架。当时的结论是KMM提倡将共有的逻辑部分抽出&#xff0c;由KMM封装成Android(Kotlin/JVM)的aar和…