
W poprzednim wpisie pokazałam jak zainstalować Neo4j. Teraz możemy spróbować napisać prostą aplikację z użyciem Spring Boot’a, która wykorzystuje bazę grafową Neo4j. Dzięki wykorzystaniu Spring Data otrzymujemy całą abstrakcję związaną z warstwą persystencji. Ponadto operacje CRUD’owe wywoływane są w taki sam sposób jak dla innych, znanych nam typów baz.
Maven
Zacznijmy od dodania zależności:
Połączenie
Aby nawiązać połączenie z bazą Neo4j należy w pliku application.properties wskazać adres, użytkownika oraz hasło:
spring.data.neo4j.uri=http://localhost:7474/
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=neo4j
Jeśli uruchamiamy bazę lokalnie na domyślnym porcie 7474 to wystarczy podać użytkownika i hasło. Domyślnie są to wartości neo4j zarówno dla użytkownika jak i hasła, ale przy pierwszym uruchomieniu bazy zostajemy poproszeni o zmianę hasła.
Mapowanie
Teraz stwórzmy klasy z węzłami i relacjami. Do mapowania obiektów na grafy wykorzystywana jest biblioteka OGM (ang. Object Graph Mapping).
Węzły
W celu oznaczenia naszej klasy POJO jako węzeł używamy adnotacji @NodeEntity. Podobnie jak w JPA domyślną nazwą węzła będzie nazwa klasy, ale możemy to zmienić ustawiając wartość label, @NodeEntity(label="Blog"). Każdy węzeł, który będzie zapisany w bazie musi posiadać unikalny identyfikator typu Long. Jeśli nazwa pola jest różna od “id” to należy użyć adnotacji @GraphId, w celu jawnego oznaczenia identyfikatora.
Relacje
Relacja może być reprezentowana przez zbiór w klasie węzła, który jest adnotowany jako @Relationship. Każda relacja musi mieć określony typ oraz kierunek. Domyślnym typem relacji jest uppercase’owana nazwa adnotowanego zbioru. Jeśli chcemy określić swój typ to umieszczamy go pod type. Z kolei domyślny kierunek relacji to OUTGOING. Inne typy ustawiamy pod direction:
- UNDIRECTED - brak zdefiniowanego kierunku relacji
- OUTGOING - relacja wychodząca z węzła
- INCOMING - relacja wchodząca do węzła
Wszystkie typy relacji dostępne są w klasie org.neo4j.ogm.annotation.Relationship, ale możemy również podać tą wartość jako String (uppercase).
@Relationship(type = “LIKE”, direction = Relationship.INCOMING)
Relacje z właściwościami
Jeśli relacja zawiera dodatkowe właściwości musimy utworzyć dla niej nową klasę z adnotacją @RelationshipEntity. Typ relacji określamy tak samo jak w przypadku @Relationship w type. Zamiast kierunku definiujemy początkowy oraz końcowy węzeł relacji poprzez adnotacje @StartNode i @EndNode.
1 | @RelationshipEntity(type = "STUDY") |
Implementacja
Zaczynamy od stworzenia klasy z węzłem Blog.
@NodeEntity
@Data
@NoArgsConstructor
public class Blog {
@GraphId
private Long blogId;
private String name;
public Blog(String name) {
this.name = name;
}
}
Drugi węzeł Subscriber posiada dodatkowo zbiór oznaczający relacje z węzłem Blog. Metoda subscribe(), pozwala nam utworzyć (dodać do zbioru) relacje pomiędzy węzłami Blog oraz Subscriber.
@NodeEntity
@Data
@NoArgsConstructor
public class Subscriber {
private Long id;
private String name;
public Subscriber(String name) {
this.name = name;
}
@Relationship(type = "LIKE")
public Set<Blog> blogs;
public void subscribe(Blog blog) {
if (blogs == null) {
blogs = new HashSet<>();
}
blogs.add(blog);
}
}
Repozytorium
Podobnie jak w innych typach baz, wykorzystujemy abstrakcję dostarczoną przez Spring Data. Nasz interfejs musi dziedziczyć po interfejsie GraphRepository. Dzięki temu otrzymujemy zbiór podstawowych metod:
interface SubscriberRepository extends GraphRepository
Subscriber findByName(String name);
}
GitHub
Cały kod z mapowaniem oraz użyciem CRUD’owych operacji znajdziecie na GitHubie.