2 분 소요


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.

댓글남기기