当前位置: 首页 > news >正文

【微服务】SpringBoot 整合Neo4j 图数据库项目实战详解

目录

一、前言

二、图数据库Neo4j 介绍

2.1 什么是图数据库

2.2 Neo4j 是什么

2.3 Neo4j 特点与功能

2.3.1 Neo4j 核心特点

2.3.2 Neo4j 核心功能

3.3 Neo4j 优点

3.4 Neo4j 核心要素

三、环境准备

3.1 Neo4j 服务搭建过程

3.1.1 下载镜像

3.1.2 创建目录

3.1.3 启动容器

3.1.4 访问neo4j web界面

四、SpringBoot 整合Neo4j

4.1 前置准备

4.1.1 版本选择

4.1.2 导入依赖

4.1.3 添加配置文件

4.2 代码整合过程

4.2.1 自定义节点与实体类映射

4.2.2 自定义jpa

4.3 代码整合测试

4.3.1 保存Person以及关系数据

4.3.2 查询数据

4.3.3 JPA自定义方法规则

五、写在文末


一、前言

随着社交,电商,金融,零售,物联网等行业的发展,现实社会的关系构成了一张复杂而庞大的关系网,而传统数据库很难处理关系运算,纵然是大数据技术,面临着数据量的不断增长时,在处理数据关系时也会面临算力的瓶颈,因此急需一种支持海量数据关系计算的数据库,图数据库就随之产生了。

二、图数据库Neo4j 介绍

2.1 什么是图数据库

图数据库(Graph Database)是一种专门用于存储和查询图结构数据的数据库。它不同于传统的关系型数据库(如 MySQL、Oracle,用表和列存储数据)和 NoSQL 数据库(如 MongoDB,用文档存储数据),其核心在于直接以“图”的方式来存储、管理和处理数据之间的关系。比如在下面这张图中,就在一张图形化的结构中很好的展示了数据之间的关系。

在这样一张关系图谱中,假如要查一下Tom Tykwer这个人与 Frank Darab 两者间的关系,使用关系型数据库来做,估计是具有的难度。

类似的关系场景还有很多,有些节点上甚至包含了很多属性值,类似这样的应用程序中,数据节点包含了大量的结构化,半结构化,甚至非结构化的连接数据。在传统的RDBMS数据库中,想要表示这种非结构化的连接数据并不简单,如果我们在RDBMS数据库中存储这种连接数据,那么检索或遍历是非常困难,而且性能是非常低效的,所以要表示或存储这种更多需要连接的数据,应该选择一个图数据库来做这件事。

使用图数据库,就能非常容易的存储这种更多需要连接的数据。它将每个配置文件数据作为节点的数据存储在内部,通过与相邻的节点连接,构成关系,这样就形成了关系图谱,检索和遍历也就非常容易且更加高效。

2.2 Neo4j 是什么

Neo4j是⽤Java实现的开源NoSQL图数据库。使用scala和java编写。从2003年开始开发,2007年正式发布第⼀版,其源码托管于GitHtb。Neo4j作为图数据库中的代表产品,已经在众多的⾏业项⽬中进⾏了应⽤,如:⽹络管理、软件分析、组织和项⽬管理、社交项⽬等⽅⾯。官网:https://neo4j.com

2.3 Neo4j 特点与功能

2.3.1 Neo4j 核心特点

Neo4j具有下面的特点:

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

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

Neo4j存储的数据格式如下图所示

2.3.2 Neo4j 核心功能

neo4j完整的功能特性总结如下:

  • SQL就像简单的查询语言,即Neo4j CQL;

  • 它遵循属性图数据模型;

  • 它通过使用Apache Lucence 支持索引;

  • 它支持UNIQUE约束;

  • 它包含一个用于执行SQL的UI界面:Neo4j浏览器;

  • 它支持完整的ACID规则;

  • 它采用原生图形库与本地GPE(图形处理引擎);

  • 它支持查询的数据导出到json和xls格式;

  • 它提供了REST API,可以被任何编程语言访问;

  • 它提供了可以通过任何UI MVC(如node js)访问的java脚本;

  • 它支持两种java api ,cypher api 和native api来访问java应用程序;

3.3 Neo4j 优点

综合来说,Neo4j具备如下优点:

  • 它很容易表示连接的数据节点之间的关系;

  • 检索/遍历/导航更多的连接数据简单而且性能高效;

  • 它很容易表示半结构化数据;

  • Neo4j CQL查询语言的命令人性化且可读性高,初学者容易掌握;

  • 数据模型简单而强大;

  • 它无需复杂的连接来检索具有关联关系的数据,因为它很容易检索临近关系的数据节点;

3.4 Neo4j 核心要素

Neo4j图数据库主要由以下元素构成,

  • 节点;

  • 属性;

  • 关系;

  • 标签;

  • 数据浏览器;

如下图所示,表示两个Person之间的关系

节点:

节点(Node)是图数据库中最基本的元素,用来表示一个实体记录,就像关系数据库库中的一条数据,在Neo4j中,一个节点可以包含多个属性和多个标签(label)。

  • 节点是主要的数据元素;

  • 节点通过关系连接到其他节点;

  • 节点可以具有一个或多个属性(即存储为键值对的属性);

  • 节点有一个或多个标签,用于描述在图表中的作用;

属性:

属性是用于描述图节点和关系的键值对,其中key为一个字符串,值可以通过使用N4o4j中支持的数据类型来表示

  • 属性是命名值,其中名称(键)是字符串;

  • 属性可以被索引和约束;

  • 可以从多个属性创建复合索引;

关系:

关系同样也是图数据库中的基本元素,当数据库中节点已经存在时,需要将节点连接起来构成图,关系就是用以连接两个节点,关系也称为图论的边,其始端和末端必须是节点,关系不能指向空也不能从空发起,关系和节点一样可以包含多个属性,但关系只能有一个类型。

  • 关系连接两个节点;

  • 关系是具有方向性的;

  • 节点可以具有多个关系甚至递归关系;

  • 关系也可以具有一个或多个属性(存储为键值对);

基于方向性,Neo4j关系主要有两种类型,

  • 单向关系;

  • 双向关系;

标签:

标签(Label)将一个公共名称与一组节点或关系相关联,节点或关系可以包含一个或多个标签,我们可以为现有的节点或关系创建新标签,也可以从现有节点或关系中删除标签。

  • 标签用于将节点分组;

  • 一个节点可以具有多个标签;

  • 对标签进行索引可以加速在图中的查找效率;

  • 本机标签索引针对速度进行了优化;

三、环境准备

为了方便在后面的程序中整合Neo4j,参考下面的流程快速搭建Neo4j服务。

3.1 Neo4j 服务搭建过程

参考下面的步骤进行搭建。

3.1.1 下载镜像

使用下面的命令下载镜像,版本可以根据自己的需要进行选择

docker pull neo4j:4.4.5

3.1.2 创建目录

创建相关的目录,如数据目录,配置文件目录等,作为与容器的映射,在usr/local下创建一个neo4j的目录,然后在neo4j目录下分别创建data、logs、conf、import 四个目录

data——数据存放的文件夹

logs——运行的日志文件夹

conf——数据库配置文件夹

import——为了大批量导入csv来构建数据库,只能导入.csv格式的文件,要放到这个文件夹下)

3.1.3 启动容器

使用下面的命令启动neo4j容器

docker run -d --name neo4j_self \
-p 7474:7474 -p 7687:7687 \
-v /usr/local/neo4j/data:/data \
-v /usr/local/neo4j/logs:/logs \
-v /usr/local/neo4j/conf:/var/lib/neo4j/conf \
-v /usr/local/neo4j/import:/var/lib/neo4j/import \
docker.io/neo4j:4.4.5

3.1.4 访问neo4j web界面

容器正常启动之后,输入本机地址加上端口号即可打开neo4j浏览器,如果是云服务器,需要提前开放上面的两个端口,如下:

默认情况下,首次登录账户/密码为,neo4j/neo4j,登录成功后,将跳转到下面的界面提示你修改密码

密码修改完成后,来到下面的界面就可以开始使用neo4j的可视化界面进行操作了。

四、SpringBoot 整合Neo4j

接下来通过实际案例演示如何在SpringBoot项目中集成和使用Neo4j

4.1 前置准备

4.1.1 版本选择

和很多其他的中间件类似,都提供了类似jpa的方式与springboot进行集成,比如大家熟悉的springdata-jpa,操作es的jpa,操作mongo的jpa等,而 Neo4j也提供了与springboot整合的jpa方式,即Spring Data Neo4j。

  • springboot版本,2.3.5

  • JKD >= 1.8

4.1.2 导入依赖

导入必须的maven依赖

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.15</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${boot-web.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-neo4j</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lomok.version}</version></dependency></dependencies>

4.1.3 添加配置文件

更多的配置参考官网,下面给出的是基本的连续配置。

server.port=8088spring.data.neo4j.uri= bolt://IP:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=neo4j

4.2 代码整合过程

在本次演示案例中,有两个节点操作对象,分别为Person和PersonRelation,两者之间具有一定的关系,然后通过程序对其完成相关的crud操作。

4.2.1 自定义节点与实体类映射

自定义Person类

@Data
@Builder
@NodeEntity("person")
public class Person implements Serializable {@Id@GeneratedValueprivate Long id;@Property("name")private String name;
}

PersonRelation类

@Data
@NoArgsConstructor
@RelationshipEntity(type = "徒弟")
public class PersonRelation implements Serializable {@Id@GeneratedValueprivate Long id;@StartNodeprivate Person parent;@EndNodeprivate Person child;@Propertyprivate String relation;public PersonRelation(Person parent, Person child, String relation) {this.parent = parent;this.child = child;this.relation = relation;}
}

4.2.2 自定义jpa

分别自定义两个操作节点对象的Repository,继承Neo4jRepository接口,使用jpa开发过的同学对此应该不陌生。

PersonRepository

public interface PersonRepository extends Neo4jRepository<Person,Long> {/*** 查询某个节点的所有子节点* @param pId* @return*/@Query("Match (p:person) -[*]->(s:person) where id(p)={0} return s")List<Person> findChildList(Long pId);@Query("Match (p:person {name:{0}}) -[*]->(s:person) return s")List<Person> findChildList(String name);/*** 查询当前节点的父节点* @param name* @return*/@Query("Match (p:person) -[*]->(s:person {name:{0}}) return p")List<Person> findParentList(String name);List<Person> findByName(String name);}

PersonRelationRepository

public interface PersonRelationRepository  extends Neo4jRepository<PersonRelation,Long> {}

4.3 代码整合测试

下面编写单元测试对上面的代码进行效果测试

4.3.1 保存Person以及关系数据

import com.congge.entity.Person;
import com.congge.entity.PersonRelation;
import com.congge.repository.PersonRelationRepository;
import com.congge.repository.PersonRepository;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;@SpringBootTest
@RunWith(SpringRunner.class)
public class PersonTest {@Autowiredprivate PersonRepository personRepository;@Autowiredprivate PersonRelationRepository personRelationRepository;@Testpublic void testSave() {Person person = Person.builder().name("唐僧").build();Person person2 = Person.builder().name("孙悟空").build();Person person3 = Person.builder().name("猪八戒").build();Person person4 = Person.builder().name("沙僧").build();Person person5 = Person.builder().name("白龙马").build();List<Person> personList = new ArrayList<>(Arrays.asList(person, person2, person3, person4, person5));personRepository.saveAll(personList);System.out.println("person 数据保存成功");PersonRelation personRelation = new PersonRelation(person, person2, "徒弟");PersonRelation personRelation2 = new PersonRelation(person, person3, "徒弟");PersonRelation personRelation3 = new PersonRelation(person, person4, "徒弟");PersonRelation personRelation4 = new PersonRelation(person, person5, "徒弟");List<PersonRelation> personRelationList = new ArrayList<>(Arrays.asList(personRelation, personRelation2, personRelation3,personRelation4));// 保存关系数据personRelationRepository.saveAll(personRelationList);System.out.println("person 关系数据保存成功");}}

运行上面的代码,效果如下:

执行成功后,可以去web界面上检查刚刚保存的数据

4.3.2 查询数据

参考下面的用例代码

@Testpublic void testDelete(){// 删除所有person节点personRepository.deleteAll();// 删除所有personRelation关系数据personRelationRepository.deleteAll();//根据id删除personRepository.deleteById(0l);}/*** 查询所有*/@Testpublic void testFindAll() {Iterable<Person> allPerson = personRepository.findAll();allPerson.forEach(item -> {System.out.println(item.getId());System.out.println(item.getName());System.out.println();});}/*** 根据id查询*/@Testpublic void testFindById() {Optional<Person> personOptional = personRepository.findById(0l);if (personOptional.isPresent()) {System.out.println(personOptional.get().getName());}}/*** 分页查询*/@Testpublic void testPage() {//设置分页、排序条件,page从0开始PageRequest pageRequest = PageRequest.of(1, 2, Sort.by(Sort.Order.desc("id")));Page<Person> page = personRepository.findAll(pageRequest);page.getContent().forEach(person -> {System.out.println(person.getId() + ":" + person.getName());});}@Testpublic void testFindByName() {List<Person> personList = personRepository.findByName("唐僧");for(Person p : personList){System.out.println(p.getName());}}

如果jpa中常用的方法还不能满足要求的话,可以尝试自定义编写语句进行实现。

4.3.3 JPA自定义方法规则

使用jpa中的规则,进行自定义查询,下面总结了一些常用的jpa使用规则,可以利用这些API完成一些更高级的业务场景开发

Keyword

Sample

Cypher snippet

After

findByLaunchDateAfter(Date date)

n.launchDate > date

Before

findByLaunchDateBefore(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)

In

findByNameIn(Iterable names)

n.name IN names

Between

findByScoreBetween(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

StartingWith

findByNameStartingWith(String nameStart)

n.name STARTS WITH nameStart

EndingWith

findByNameEndingWith(String nameEnd)

n.name ENDS WITH nameEnd

Exists

findByNameExists()

EXISTS(n.name)

True

findByActivatedIsTrue()

n.activated = true

False

findByActivatedIsFalse()

NOT(n.activated = true)

Is

findByNameIs(String name)

n.name = name

NotNull

findByNameNotNull()

NOT(n.name IS NULL)

Null

findByNameNull()

n.name IS NULL

GreaterThan

findByScoreGreaterThan(double score)

n.score > score

GreaterThanEqual

findByScoreGreaterThanEqual(double score)

n.score >= score

LessThan

findByScoreLessThan(double score)

n.score < score

LessThanEqual

findByScoreLessThanEqual(double score)

n.score <= score

Like

findByNameLike(String name)

n.name =~ name

NotLike

findByNameNotLike(String name)

NOT(n.name =~ name)

Near

findByLocationNear(Distance distance, Point point)

distance( point(n),point({latitude:lat, longitude:lon}) ) < distance

Regex

findByNameRegex(String regex)

n.name =~ regex

And

findByNameAndDescription(String name, String description)

n.name = name AND n.description = description

Or

findByNameOrDescription(String name, String description)

n.name = name OR n.description = description (Cannot be used to OR nested properties)

五、写在文末

本文详细总结了如何在springboot中集成与使用neo4j,并通过代码演示了如何使用,更多的用法有兴趣的同学还可以深入研究。本篇到此结束,感谢观看。

http://www.dtcms.com/a/544392.html

相关文章:

  • 模板网站系统wordpress首页描述
  • 图书网站策划书网站的维护方案
  • 【Android】Android Framework 的那些核心子系统及其功能详解
  • Android车载多媒体开发MediaSession框架理解
  • 掌握Axios:前端HTTP请求全攻略
  • 产业链、技术与政策:智能网联新能源汽车的“十五五”蓝图
  • 20251029让AIO-3576Q38开发板适配Rockchip的原厂Android14之后配置为禁止锁屏
  • 解析视频融合平台EasyCVR如何以跨平台与兼容性技术重构安防融合中台
  • SQlite:外键约束
  • linux命令-网络工具-3
  • Android 通信机制简析
  • C++ 虚函数的使用开销以及替代方案
  • 椒江网站建设百度手机助手app安卓版官方下载
  • 柯桥做网站的公司怎么查网站是用什么语言做的
  • Unity功能篇:UI和模型高亮
  • Rust | 不只是 async:Actix-web 请求生命周期与 Actor 模型的并发艺术
  • 如何选择专业网站开发商丰台建站推广
  • Kotlin List扩展函数使用指南
  • 重组蛋白与传统蛋白的区别:从来源到特性的全面解析
  • Ubuntu24.04 最小化发布 需要删除的内容
  • 深入理解 Rust 的 LinkedList:双向链表的实践与思考
  • 将一个List分页返回的操作方式
  • 使用Storage Transfer Service 事件驱动型 — 将AWS S3迁移到 GCP Cloud Storage
  • 苏州外贸网站建设赣州网上银行登录
  • Blender动画笔记
  • python学习之正则表达式
  • SCRM平台对比推荐:以企业微信私域运营需求为核心的参考
  • 廊坊网站搭建别墅装修案例
  • select/poll/epoll
  • VTK开发笔记(八):示例Cone5,交互器的实现方式,在Qt窗口中详解复现对应的Demo