Spring-Boot+Neo4j☞节点关系的创建和查询


一、项目目录结构图







二、pom



<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.appleyk</groupId>
	<artifactId>Spring-Boot-Neo4j</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<description>Spring-Boot 集成 Neo4j图形数据库实现关系的构建与查询</description>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.12.RELEASE</version>
	</parent>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<!-- Starter POMs是可以包含到应用中的一个方便的依赖关系描述符集合 -->
	<!-- 该Starters包含很多你搭建项目, 快速运行所需的依赖, 并提供一致的, 管理的传递依赖集。 -->
	<!-- 大多数的web应用都使用spring-boot-starter-web模块进行快速搭建和运行。 -->
	<!-- spring-boot-starter-web -->
	<!-- 对全栈web开发的支持, 包括Tomcat和 spring-webmvc -->
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- 添加热部署 devtools:监听文件变动 -->
		<!-- 当Java文件改动时,Spring-boo会快速重新启动 -->
		<!-- 最简单的测试,就是随便找一个文件Ctrl+S一下,就可以看到效果 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<!-- optional=true,依赖不会传递 -->
			<!-- 本项目依赖devtools;若依赖本项目的其他项目想要使用devtools,需要重新引入 -->
			<optional>true</optional>
		</dependency>
		<!-- Spring 单元测试 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- JUnit单元测试 -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>
		<!-- 图形数据库Neo4j 官方支持的neo4j依赖包 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-neo4j</artifactId>
		</dependency>
	</dependencies>
</project>



三、配置文件


server.port=8080
server.session.timeout=10
server.tomcat.uri-encoding=utf8

#在application.properties文件中引入日志配置文件
#=====================================  log  =============================
logging.config=classpath:logback-boot.xml

#Neo4j配置
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=n123
#数据库uri地址 
spring.data.neo4j.uri=http://localhost:7474


Application.java



package com.appleyk;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;


@SpringBootApplication// same as @Configuration @EnableAutoConfiguration  @ComponentScan	
public class Application extends SpringBootServletInitializer{

	public static void  main(String[] args) {      		
		SpringApplication.run(Application.class, args);			
	}	
	
	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(Application.class);
	}
}



四、节点实体类



(1)抽象父类:BaseNode .java


package com.appleyk.node;

import org.neo4j.ogm.annotation.GraphId;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public abstract class BaseNode {

	@GraphId
	private Long id;
	protected String name;

	public BaseNode() {
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}


(2)子类:User.java


package com.appleyk.node;

import java.util.ArrayList;
import java.util.List;

import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;

import com.appleyk.relation.LikeRelation;

@NodeEntity
public class User extends BaseNode{

	/**
	 * 用户ID
	 */
	private Long uid;
	
	/**
	 * 用户性别
	 */
	private String sex;
	
	/**
	 * 用户年龄
	 */
	private Integer age;
	
	/**
	 * 兴趣爱好
	 */
	private List<String> hobbies;
	
	/**
	 * 添加关系喜欢,方向为  ->,表明当前节点是startNode
	 */
	@Relationship(type="Like",direction = Relationship.OUTGOING)
	private List<LikeRelation> likes;
	

	
	public User(){
		hobbies = new ArrayList<>();
		likes = new ArrayList<>();
	}
	
	public Long getUid() {
		return uid;
	}

	public void setUid(Long uid) {
		this.uid = uid;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public List<String> getHobbies() {
		return hobbies;
	}

	public void setHobbies(List<String> hobbies) {
		this.hobbies = hobbies;
	}
	
	public void addHobby(String hobby){
		hobbies.add(hobby);
	}
		
	public void addLikes(User user,String reason,Integer since,Integer relationID){
		LikeRelation like = new LikeRelation(this, user, reason, since, relationID);
		this.likes.add(like);
	}
}



五、关系实体类



LikeRelation.java


package com.appleyk.relation;

import org.neo4j.ogm.annotation.EndNode;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.Property;
import org.neo4j.ogm.annotation.RelationshipEntity;
import org.neo4j.ogm.annotation.StartNode;

import com.appleyk.node.BaseNode;

@RelationshipEntity(type = "Like")
public class LikeRelation {

	@GraphId
	private Long id;

	/**
	 * 定义关系的起始节点 == StartNode
	 */

	@StartNode
	private BaseNode startNode;

	/**
	 * 定义关系的终止节点 == EndNode
	 */

	@EndNode
	private BaseNode endNode;

		
	/**
	 * 定义关系的属性
	 */

	@Property(name = "reason")
	private String  reason;
	@Property(name = "since")
	private Integer since;
	@Property(name = "relationID")
	private Integer relationID;

	public LikeRelation() {
	}
	
	public LikeRelation(BaseNode startNode,BaseNode endNode,String reason,
			Integer since,Integer relationID){
		this.startNode = startNode;
		this.endNode = endNode;
		this.reason = reason;
		this.since = since;
		this.relationID = relationID;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public BaseNode getStartNode() {
		return startNode;
	}

	public void setStartNode(BaseNode startNode) {
		this.startNode = startNode;
	}

	public BaseNode getEndNode() {
		return endNode;
	}

	public void setEndNode(BaseNode endNode) {
		this.endNode = endNode;
	}

	public String getReason() {
		return reason;
	}

	public void setReason(String reason) {
		this.reason = reason;
	}

	public Integer getSince() {
		return since;
	}

	public void setSince(Integer since) {
		this.since = since;
	}

	public Integer getRelationID() {
		return relationID;
	}

	public void setRelationID(Integer relationID) {
		this.relationID = relationID;
	}
	
}


六、节点User接口



UserRepository.java


package com.appleyk.repository;

import java.util.List;

import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import com.appleyk.node.User;

@Repository
public interface UserRepository extends GraphRepository<User>{

	List<User> getUsersByName(@Param("name") String name);
	
	/**
	 * 根据年龄查询用户节点
	 * @param age
	 * @return
	 */
	@Query("match(n:User) where n.age >{age} return n")
	List<User> getUsers(@Param("age") Integer age);
}




七、关系Like接口



LikeRelationRepository.java


package com.appleyk.repository;

import java.util.List;

import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.GraphRepository;

import com.appleyk.relation.LikeRelation;

public interface LikeRelationRepository extends GraphRepository<LikeRelation>{

	/**
	 * 查询关系
	 * @param relationName
	 * @return
	 */
	@Query("match p = (n)-[r:Like]->(b) return p")
	List<LikeRelation> getLikes();
	
	
	/**
	 * 为两个已经存在的节点添加关系
	 * @param startNodeID -- 起始节点
	 * @param endNodeID   -- 终止节点
	 * @param rID         -- 关系的ID
	 * @param year        -- 关系的开始年限
	 * @param reason	  -- 关系产生的原因
	 * @return
	 */
	@Query("match(a),(b) where a.uid={0} and b.uid = {1}"
			+ " create p = (a)-[r:Like{relationID:{2},since:{3},reason:{4}}]->(b) return p ")
	List<LikeRelation> createLikes(Long startNodeID,Long endNodeID,
								   Integer rID,Integer year,String reason);
}



八、neo4j查询关系语句




例如:match p =(n)-[r:Like]-(b) return p







九、单元测试User节点的创建和查询



UserNodeTest.java


import java.util.ArrayList;
import java.util.List;

import org.junit.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.SpringJUnit4ClassRunner;

import com.appleyk.Application;
import com.appleyk.node.User;
import com.appleyk.relation.LikeRelation;
import com.appleyk.repository.UserRepository;


@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=Application.class) 
public class UserNodeTest {

	
	@Autowired
	UserRepository userRepository;
	
	/**
	 * 创建用户节点 【批量创建】 
	 * @throws Exception
	 */
	@Test
	public void createUser() throws Exception{	
		
		List<User> userNodes = new ArrayList<>();		
		User userNode1 = new User();
		userNode1.setUid(1001L);
		userNode1.setName("刘大壮");
		userNode1.setAge(22);
		userNode1.setSex("男");
		userNode1.addHobby("游戏");
		userNode1.addHobby("睡觉");
		userNode1.addHobby("撸串");
		
		User userNode2 = new User();
		userNode2.setUid(1002L);
		userNode2.setName("马晓丽");
		userNode2.setAge(17);
		userNode2.setSex("女");
		userNode2.addHobby("逛街");
		userNode2.addHobby("美食");
		userNode2.addHobby("化妆");
		
		userNodes.add(userNode1);
		userNodes.add(userNode2);			
		Iterable<User> iterable = userRepository.save(userNodes);		
		for (User user : iterable) {
			System.out.println("创建节点:【"+user.getName()+"】成功!");
		}
		
	}
	
	/**
	 * 创建节点  == 内置关系
	 */
	@Test
	public void createNodeandRelation(){
			
		User startNode = new User();
		startNode.setUid(1011L);
		startNode.setName("刘泽");
		startNode.setAge(22);
		startNode.setSex("男");
		startNode.addHobby("游戏");
		startNode.addHobby("睡觉");
		
		User endNode1 = new User();
		endNode1.setUid(1012L);
		endNode1.setName("张婷");
		endNode1.setAge(17);
		endNode1.setSex("女");
		endNode1.addHobby("逛街");
		endNode1.addHobby("美食");
		endNode1.addHobby("化妆");
		
		User endNode2 = new User();
		endNode2.setUid(1013L);
		endNode2.setName("林志玲");
		endNode2.setAge(45);
		endNode2.setSex("女");
		endNode2.addHobby("逛街");
		endNode2.addHobby("美食");
		endNode2.addHobby("化妆");
		
		startNode.addLikes(endNode1, "心地善良,人美", 2015,521 );
		startNode.addLikes(endNode2, "女神姐姐", 2011, 520);
		
		User userNode = userRepository.save(startNode);
		System.out.println("节点"+userNode.getName()+"创建成功!");
		
	}
	
	/**
	 * 根据用户的name查询user节点列表
	 */
	@Test
	public void findUserByName(){
		List<User> users = userRepository.getUsersByName("刘大壮");
		System.out.println("共查出来节点有:"+users.size()+"个");
	}
	
	/**
	 * 根据用户的年龄查询user节点【年龄大于18】
	 */
	@Test
	public void findUserByAge(){
		List<User> users = userRepository.getUsers(18);
		for (User user : users) {
			System.out.println("共查出来节点有:"+users.size()+"个, == "+user.getName());
		}
	}
}



十、单元测试Like关系的创建与查询



关系的添加语句:


match(a),(b) where a.uid = 1001 and b.uid = 1002 

create p=(a)-[r:Like{relationID:520,since:2018,reason:'晓丽是女神'}]->(b) return p


LikeRelationTest.java


import java.util.List;

import org.junit.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.SpringJUnit4ClassRunner;

import com.appleyk.Application;
import com.appleyk.node.User;
import com.appleyk.relation.LikeRelation;
import com.appleyk.repository.LikeRelationRepository;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class LikeRelationTest {

	@Autowired
	private LikeRelationRepository likeRepository;


	/**
	 * 在已有的两个节点的基础上创建关系
	 */
	@Test
	public void createLikeRelation() throws Exception {

		LikeRelation like = new LikeRelation();

		/**
		 * 节点 == 刘大壮
		 */
		User startNode = new User();
		startNode.setUid(1001L);

		/**
		 * 节点 == 马晓丽
		 */
		User endNode = new User();
		endNode.setUid(1002L);

		like.setStartNode(startNode);
		like.setEndNode(endNode);

		like.setRelationID(520);
		like.setSince(2018);
		like.setReason("晓丽是女神");

		List<LikeRelation> likes = likeRepository.createLikes(startNode.getUid(), 
				endNode.getUid(), like.getRelationID(),like.getSince(),like.getReason());	
		
		/**
		 * 遍历创建的关系
		 */
		for (LikeRelation likeRelation : likes) {
			User sNode = (User) likeRelation.getStartNode();
			User eNode = (User) likeRelation.getEndNode();
			System.out.println(sNode.getName() + "--喜欢-->" + eNode.getName());
		}
	}
	
	
	/**
	 * 创建节点并创建关系
	 */
	@Test
	public void createLikes(){
		LikeRelation like = new LikeRelation();

		/**
		 * 节点 == 韩梅梅
		 */
		User startNode = new User();
		startNode.setUid(1003L);
		startNode.setName("韩梅梅");
		startNode.setAge(18);
		startNode.setSex("女");
		startNode.addHobby("看书");
		startNode.addHobby("逛街");
		
		/**
		 * 节点 == 李晓明
		 */
		User endNode = new User();
		endNode.setUid(1004L);
		endNode.setName("李晓明");
		endNode.setAge(19);
		endNode.setSex("男");
		endNode.addHobby("游戏");
		endNode.addHobby("音乐");
		endNode.addHobby("篮球");
		
		like.setStartNode(startNode);
		like.setEndNode(endNode);

		like.setRelationID(520);
		like.setSince(2018);
		like.setReason("晓明好帅啊");
		
		LikeRelation relation = likeRepository.save(like);
		System.out.println(relation.getStartNode().getName()+"-->喜欢"+
		relation.getEndNode().getName()+",理由:"+relation.getReason());
		
	}
	
	/**
	 * 查询关系
	 */
	@Test
	public void findLikes(){
		List<LikeRelation> likes = likeRepository.getLikes();
		for (LikeRelation likeRelation : likes) {
			User sNode = (User) likeRelation.getStartNode();
			User eNode = (User) likeRelation.getEndNode();
			System.out.println(sNode.getName() + "--喜欢-->" + eNode.getName()+" == reason: "+likeRelation.getReason());
		}
	}

}



十一、效果演示


创建前清空测试数据的cypher语句:match(n)-[r:Like]-(b) delete n,r,b



(1)创建节点 == 不内置关系











(2)查询年龄大于18岁的user节点







(3)创建节点 == 内置关系的创建









(4)刘大壮喜欢马晓丽,我们为这两个节点创建Like关系,并连带关系的属性一起创建










(5)再创建一个关系,创建关系的同时,创建关系中的startNode和endNode














(6)查询关系Like










十二、项目地址



博主注:neo4j关系其实就是由两个node加一个边edge组成的,关系是有向的,因此,node分起始startNode和终止endNode,通俗点就是源节点到目标节点之间存在一条边,这个边就是关系relation,其查询cypher语句的模板为:


match path =(a)-[r] - (b)  return path


在neo4j的关系查询中,关系默认是不区分方向的,因为a和b存在关系r,反过来b和a之间理论上也是存在关系的,除非你指定关系的方向,否则查询的时候会出现正反两条结果,但是显示关系【可视化】的时候,却是有方向的


比如查询语句:match path =(a)-[:Like] -> (b)  return path 的结果为:


 




如果不指定关系的方向查询的话,其语句:match path =(a)-[:Like] - (b)  return path 的结果为:





由于demo中我们在定义关系实体的时候,指定了startNode和endNode,这就表明,即使查询语句不指定关系,但是在结果返回的时候,匹配节点的时候,还是会隐式的暴露关系的方向







GitHub地址:Spring-Boot 集成 Neo4j图形数据库实现关系的构建与查询




  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
首先,需要在 `pom.xml` 文件中添加 Neo4j 的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-neo4j</artifactId> </dependency> ``` 然后,在 `application.properties` 文件中添加 Neo4j 的配置: ```properties spring.data.neo4j.uri=bolt://localhost:7687 spring.data.neo4j.username=neo4j spring.data.neo4j.password=password ``` 接下来,在你的实体类中,可以使用注解来定义节点关系。例如,下面是一个简单的示例: ```java @NodeEntity public class Person { @Id @GeneratedValue private Long id; @Property(name = "name") private String name; @Relationship(type = "FRIEND") private List<Person> friends; // getters and setters omitted for brevity } ``` 在上面的示例中,`@NodeEntity` 注解表示这是一个节点实体类,`@Id` 注解表示该节点的唯一标识符,`@Property` 注解表示该节点的属性,`@Relationship` 注解表示该节点与其他节点之间的关系。 为了导入数据,你需要使用 `Neo4jRepository` 接口的方法,例如 `save()` 和 `saveAll()`。下面是一个简单的示例: ```java @Service public class PersonService { @Autowired private PersonRepository personRepository; public void savePerson(Person person) { personRepository.save(person); } public void savePersons(List<Person> persons) { personRepository.saveAll(persons); } } ``` 在上面的示例中,`PersonRepository` 是一个继承自 `Neo4jRepository` 的接口,它提供了许多用于操作节点关系的方法。 最后,你可以在你的应用程序中调用 `PersonService` 的方法来创建实体节点和导入数据。 ```java @RestController public class MyController { @Autowired private PersonService personService; @PostMapping("/person") public void createPerson(@RequestBody Person person) { personService.savePerson(person); } @PostMapping("/persons") public void createPersons(@RequestBody List<Person> persons) { personService.savePersons(persons); } } ``` 在上面的示例中,`MyController` 是一个简单的控制器,它允许你通过 HTTP 请求来创建实体节点和导入数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值