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.properties
를 application.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"을 넣고,
TEAMMATE
를workWith(..)
함수로 추가하고 있는 코드를 확인할 수 있다. - 결과로는 각 사람의 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를 확인할 수 있다.
참조
- Getting Started | Accessing Data with Neo4j
- 공식 문서에도 불구하고 내용하고 코드가 안맞는 부분이 많았다.
위에 예제 코드는 GitHub에서 확인해 볼 수 있다.