Spring Data Neo4j - Neo4j 데이터 추가 및 조회

spring Data Neo4j는 그래프 데이터베이스 중에 하나인 neo4j에 다루는 프레임워크 이다.

개요

Neo4j는 그래프 데이터베이스 중에 하나이며, Spring Data에서는 Neo4j를 다를 수 있는 인테페이스를 제공하는 프레임워크를 제공한다.

Kotlin 언어를 이용하여 간단한 Spring Data Neo4j 활용한 프로젝트를 만들어 보겠다.

Neo4j 서버 준비

Neo4j는 오픈 소스 서버이기에 무료로 설치하거나, Docker로 실행할 수 있다.

Neo4j macOS 환경에서는 3가지 설치 방법이 있다.

본인에 원하는 방식으로 설치를 해도 상관 없다.

Neo4j 프로젝트 생성

아래와 같이 curl 명령어를 사용하여 Spring Boot 초기 프로젝트를 생성한다.

curl https://start.spring.io/starter.tgz \ -d bootVersion=3.0.6 \ -d dependencies=data-neo4j \ -d baseDir=spring-data-neo4j \ -d groupId=com.devkuma \ -d artifactId=spring-data-neo4j \ -d packageName=com.devkuma.neo4j \ -d applicationName=Neo4jApplication \ -d packaging=jar \ -d language=kotlin \ -d javaVersion=17 \ -d type=gradle-project-kotlin | tar -xzvf -

위 명령어를 실행하게 되면 Java 17, Spring Boot 버전은 3.0.6으로 프로젝트가 생성된다.

빌드 스크립트

빌드 스크립트에 Neo4j을 동작시키기 위한 라이브러리를 아래와 같이 추가한다.

/build.gradle.kts

dependencies { implementation("org.springframework.boot:spring-boot-starter-data-neo4j") implementation("org.jetbrains.kotlin:kotlin-reflect") testImplementation("org.springframework.boot:spring-boot-starter-test") }

의존성 라이브러리에 Spring Data Neo4j 라이브러리(spring-boot-starter-data-neo4j)가 포함된 것을 볼 수 있다.

Entity 정의

Neo4j는 엔터티와 엔터티의 관계를 연결되며, 두 방향 모두 똑같이 중요한다. 각 사람에 대한 레코드를 저장하는 시스템을 모델링한다고 생각해 보자. 여기서 특정 사람의 동료도 추적하려고 한다. 예를 들어, 아래 엔티티에서 teammates에 해당된다.

src/main/java/com/devkuma/neo4j/entity/Person.java

package com.devkuma.neo4j.entity import org.springframework.data.neo4j.core.schema.GeneratedValue import org.springframework.data.neo4j.core.schema.Id import org.springframework.data.neo4j.core.schema.Node import org.springframework.data.neo4j.core.schema.Relationship import java.util.* import java.util.stream.Collectors @Node class Person { @Id @GeneratedValue var id: Long = 0 var name: String = "" @Relationship(type = "TEAMMATE") var teammates: MutableSet<Person>? = null fun worksWith(person: Person) { if (teammates == null) { teammates = HashSet() } teammates!!.add(person) } override fun toString(): String { return ("$name's teammates => " + Optional .ofNullable(teammates) .orElse(mutableSetOf()).stream() .map { obj: Person -> obj.name } .collect(Collectors.toList())) } }

쿼리 Repository 생성

Spring Data Neo4j는 Neo4j에 데이터를 저장하는데 중점을 둔다. 그러나 조회 쿼리 파생 기능을 포함하여 Spring Data Commons 프로젝트의 기능을 상속받는다. 기본적으로 Neo4j의 쿼리 언어를 배울 필요가 없다. 대신 몇 가지 메서드를 작성해야 쿼리가 자동으로 작성되도록 할 수 있다.

src/main/java/com/devkuma/neo4j/repository/PersonRepository.java

package com.devkuma.neo4j.repository import com.devkuma.neo4j.entity.Person import org.springframework.data.neo4j.repository.Neo4jRepository interface PersonRepository : Neo4jRepository<Person, Long> { fun findByName(name: String): Person? fun findByTeammatesName(name: String): List<Person> }

PersonRepository 인터페이스는 Neo4jRepository 확장하고, 작동하려는 유형(Person)을 연결한다. 이 인터페이스는 표준 CRUD(만들기, 읽기, 업데이트 및 삭제) 작업을 비롯한 많은 작업과 함께 제공된다.

Neo4j 접근 권한

Neo4j Community Edition에 접근하려면 자격 증명 설정이 필요하다. spring 기본 설정 파일인 application.propertiesapplication.yml로 변경하고 아래와 같이 설정을 넣는다.

/src/main/resources/application.yml

spring: neo4j: uri: bolt://localhost:7687 authentication: username: neo4j password: secret123

로그 설정

로그를 표시하기 위해 의존성으로 kotlin-logging 라이브러리를 추가한다.

dependencies { // .. 생략 .. implementation("io.github.microutils:kotlin-logging:3.0.5") }

그리고, Spring 설정 파일에 로그 Level를 설정한다.

logging: level: org.springframework.data.neo4j.cypher: ERROR

이 설정이 없으면 cypher 관련 WARN이 발생한다. (아무래도, Spring Data Neo4j 업데이트가 필요해 보인다.)

애플리케이션 클래스 생성

Spring Initializr는 애플리케이션을 위한 간단한 클래스를 생성해준다.

src/main/java/com/devkuma/neo4j/entity/Person.java

package com.devkuma.neo4j import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @SpringBootApplication class Neo4Ajpplication fun main(args: Array<String>) { runApplication<Neo4Ajpplication>(*args) }

이 생성된 애플리케이션 클래스를 아래와 같이 변경한다.

package com.devkuma.neo4j import com.devkuma.neo4j.entity.Person import com.devkuma.neo4j.repository.PersonRepository import mu.KotlinLogging import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.CommandLineRunner import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication import org.springframework.context.annotation.Bean import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories import kotlin.system.exitProcess private val log = KotlinLogging.logger {} @SpringBootApplication @EnableNeo4jRepositories class Neo4jApplication { @Bean fun demo(@Autowired personRepository: PersonRepository): CommandLineRunner { return CommandLineRunner { personRepository.deleteAll() var greg = Person() greg.name = "Greg" var roy = Person() roy.name = "Roy" val craig = Person() craig.name = "Craig" val team: List<Person> = listOf(greg, roy, craig) log.info("Before linking up with Neo4j...") team.stream().forEach { person: Person -> log.info("\t${person}") } personRepository.save(greg) personRepository.save(roy) personRepository.save(craig) greg = personRepository.findByName(greg.name)!! greg.worksWith(roy) greg.worksWith(craig) personRepository.save(greg) roy = personRepository.findByName(roy.name)!! roy.worksWith(craig) personRepository.save(roy) log.info("Lookup each person by name...") team.stream().forEach { person: Person -> log.info("\t${personRepository.findByName(person.name)}") } val teammates = personRepository.findByTeammatesName(craig.name) log.info("The following have ${craig.name} as a teammate...") teammates.stream() .forEach { person: Person -> log.info("\t${person.name}") } } } } fun main(args: Array<String>) { runApplication<Neo4jApplication>(*args) exitProcess(0) }
  • @EnableNeo4jRepositories
    • 이 어노테이션이 있으므써, Neo4j 설정이 활성화 된다.
  • 초기에는 모두 데이터를 삭제하고, “Greg”, “Roy”, “Craing"을 넣고, TEAMMATEworkWith(..) 함수로 추가하고 있는 코드를 확인할 수 있다.
  • 결과로는 각 사람의 teammates를 표시해주고, 반대로 “Craig"를 teammate로 지정한 사람을 표시해주고 있다.

애플리케이션 실행

그럼 실행을 해보면, 결과가 로그로 표시되는 것을 볼 수 있다.

2023-05-13T01:53:34.640+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : Before linking up with Neo4j...
2023-05-13T01:53:34.640+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : 	Greg's teammates => []
2023-05-13T01:53:34.640+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : 	Roy's teammates => []
2023-05-13T01:53:34.640+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : 	Craig's teammates => []
2023-05-13T01:53:34.852+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : Lookup each person by name...
2023-05-13T01:53:34.865+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : 	Greg's teammates => [Craig, Roy]
2023-05-13T01:53:34.874+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : 	Roy's teammates => [Craig]
2023-05-13T01:53:34.881+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : 	Craig's teammates => []
2023-05-13T01:53:34.893+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : The following have Craig as a teammate...
2023-05-13T01:53:34.894+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : 	Greg
2023-05-13T01:53:34.894+09:00  INFO 36427 --- [           main] com.devkuma.neo4j.Neo4jApplication       : 	Roy

Neo4j Browser(http://localhost:7474/browser/)에 접속해 보면 Node List를 확인할 수 있다.

Accessing Data Neo4j

참조

위에 예제 코드는 GitHub에서 확인해 볼 수 있다.




최종 수정 : 2024-01-18