4 분 소요


Getting Started with Neo4j and Spring Boot

Neo4j is a graph database that excels at handling connected data. Spring Data Neo4j provides seamless integration with Spring Boot, making it straightforward to work with graph data using familiar Spring patterns.

1. Dependencies

Add the Spring Data Neo4j starter to pom.xml:

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

For Gradle:

implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'

2. Configuration

Configure the connection in application.yml:

spring:
  neo4j:
    uri: bolt://localhost:7687
    authentication:
      username: neo4j
      password: your-password

For local development, run Neo4j with Docker:

docker run -d \
  --name neo4j \
  -p 7474:7474 -p 7687:7687 \
  -e NEO4J_AUTH=neo4j/your-password \
  neo4j:5

Port 7474 serves the browser interface, 7687 is for Bolt protocol connections.

3. Defining Nodes

Create an entity class with @Node:

@Node
public class Person {

    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private Integer age;

    @Relationship(type = "FRIEND_OF", direction = Direction.OUTGOING)
    private List<Person> friends = new ArrayList<>();

    // constructors, getters, setters
}

The @Relationship annotation defines edges in the graph. Direction matters—OUTGOING means this person has friends, INCOMING would mean others consider this person a friend.

4. Repository

Spring Data Neo4j repositories work like JPA repositories:

public interface PersonRepository extends Neo4jRepository<Person, Long> {

    Optional<Person> findByName(String name);

    @Query("MATCH (p:Person)-[:FRIEND_OF]->(f:Person) WHERE p.name = $name RETURN f")
    List<Person> findFriendsOf(String name);
}

Derived query methods work out of the box. For complex traversals, use @Query with Cypher.

5. Basic Cypher Queries

Cypher is Neo4j’s query language. A few essential patterns:

Create a node:

CREATE (p:Person {name: 'Alice', age: 30})

Create a relationship:

MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
CREATE (a)-[:FRIEND_OF]->(b)

Find friends of friends:

MATCH (p:Person {name: 'Alice'})-[:FRIEND_OF]->()-[:FRIEND_OF]->(fof)
WHERE fof <> p
RETURN DISTINCT fof.name

The arrow syntax ()-[]->() represents traversal direction. Variable-length paths use *: [:FRIEND_OF*2] means exactly 2 hops.

6. Service Layer

@Service
@Transactional
public class PersonService {

    private final PersonRepository repository;

    public PersonService(PersonRepository repository) {
        this.repository = repository;
    }

    public Person create(String name, int age) {
        Person person = new Person(name, age);
        return repository.save(person);
    }

    public void addFriend(String personName, String friendName) {
        Person person = repository.findByName(personName)
            .orElseThrow(() -> new RuntimeException("Person not found"));
        Person friend = repository.findByName(friendName)
            .orElseThrow(() -> new RuntimeException("Friend not found"));

        person.getFriends().add(friend);
        repository.save(person);
    }

    public List<Person> getFriends(String name) {
        return repository.findFriendsOf(name);
    }
}

The @Transactional annotation ensures relationship modifications are atomic.

7. When to Use Neo4j

Graph databases shine for:

  • Social networks (friends, followers, connections)
  • Recommendation engines (users who bought X also bought Y)
  • Fraud detection (finding suspicious patterns in transactions)
  • Knowledge graphs and hierarchies

For simple CRUD with no complex relationships, a relational database is simpler. Neo4j adds value when queries involve traversing multiple relationship levels.

8. Conclusion

Spring Data Neo4j provides a clean abstraction over Neo4j. Define nodes with @Node, relationships with @Relationship, and use repositories for basic operations. For complex graph traversals, Cypher queries offer full control.

Neo4j와 Spring Boot 시작하기

Neo4j는 연결된 데이터를 다루는 데 특화된 그래프 데이터베이스다. Spring Data Neo4j는 Spring Boot와 자연스럽게 통합되어, 익숙한 Spring 패턴으로 그래프 데이터를 다룰 수 있게 해준다.

1. 의존성

pom.xml에 Spring Data Neo4j 스타터를 추가한다:

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

Gradle의 경우:

implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'

2. 설정

application.yml에서 연결을 설정한다:

spring:
  neo4j:
    uri: bolt://localhost:7687
    authentication:
      username: neo4j
      password: your-password

로컬 개발 환경에서는 Docker로 Neo4j를 실행할 수 있다:

docker run -d \
  --name neo4j \
  -p 7474:7474 -p 7687:7687 \
  -e NEO4J_AUTH=neo4j/your-password \
  neo4j:5

7474 포트는 브라우저 인터페이스, 7687은 Bolt 프로토콜 연결용이다.

3. 노드 정의

@Node로 엔티티 클래스를 만든다:

@Node
public class Person {

    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private Integer age;

    @Relationship(type = "FRIEND_OF", direction = Direction.OUTGOING)
    private List<Person> friends = new ArrayList<>();

    // constructors, getters, setters
}

@Relationship 어노테이션은 그래프의 엣지를 정의한다. 방향이 중요한데, OUTGOING은 이 사람이 친구를 가지고 있음을, INCOMING은 다른 사람들이 이 사람을 친구로 여긴다는 것을 의미한다.

4. Repository

Spring Data Neo4j repository는 JPA repository와 동일하게 동작한다:

public interface PersonRepository extends Neo4jRepository<Person, Long> {

    Optional<Person> findByName(String name);

    @Query("MATCH (p:Person)-[:FRIEND_OF]->(f:Person) WHERE p.name = $name RETURN f")
    List<Person> findFriendsOf(String name);
}

메서드 이름 기반 쿼리가 기본으로 동작한다. 복잡한 탐색에는 @Query와 Cypher를 사용한다.

5. 기본 Cypher 쿼리

Cypher는 Neo4j의 쿼리 언어다. 필수 패턴 몇 가지:

노드 생성:

CREATE (p:Person {name: 'Alice', age: 30})

관계 생성:

MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
CREATE (a)-[:FRIEND_OF]->(b)

친구의 친구 찾기:

MATCH (p:Person {name: 'Alice'})-[:FRIEND_OF]->()-[:FRIEND_OF]->(fof)
WHERE fof <> p
RETURN DISTINCT fof.name

화살표 문법 ()-[]->() 는 탐색 방향을 나타낸다. 가변 길이 경로는 *를 사용한다: [:FRIEND_OF*2]는 정확히 2홉을 의미한다.

6. Service 계층

@Service
@Transactional
public class PersonService {

    private final PersonRepository repository;

    public PersonService(PersonRepository repository) {
        this.repository = repository;
    }

    public Person create(String name, int age) {
        Person person = new Person(name, age);
        return repository.save(person);
    }

    public void addFriend(String personName, String friendName) {
        Person person = repository.findByName(personName)
            .orElseThrow(() -> new RuntimeException("Person not found"));
        Person friend = repository.findByName(friendName)
            .orElseThrow(() -> new RuntimeException("Friend not found"));

        person.getFriends().add(friend);
        repository.save(person);
    }

    public List<Person> getFriends(String name) {
        return repository.findFriendsOf(name);
    }
}

@Transactional 어노테이션은 관계 수정이 원자적으로 이루어지도록 보장한다.

7. Neo4j를 사용해야 할 때

그래프 데이터베이스가 빛을 발하는 경우:

  • 소셜 네트워크 (친구, 팔로워, 연결)
  • 추천 엔진 (X를 산 사용자가 Y도 구매함)
  • 사기 탐지 (거래에서 의심스러운 패턴 찾기)
  • 지식 그래프와 계층 구조

복잡한 관계 없이 단순 CRUD만 필요하다면 관계형 데이터베이스가 더 간단하다. Neo4j는 여러 단계의 관계를 탐색하는 쿼리가 필요할 때 가치를 발휘한다.

8. 결론

Spring Data Neo4j는 Neo4j에 대한 깔끔한 추상화를 제공한다. @Node로 노드를, @Relationship으로 관계를 정의하고, repository로 기본 작업을 처리한다. 복잡한 그래프 탐색에는 Cypher 쿼리가 완전한 제어권을 제공한다.

댓글남기기