«1. Обзор

Эта статья представляет собой введение в Spring Data Neo4j, популярную графовую базу данных.

Spring Data Neo4j обеспечивает разработку на основе POJO для базы данных Neo4j Graph и использует знакомые концепции Spring, такие как классы шаблонов для использования основного API, и предоставляет модель программирования на основе аннотаций.

Кроме того, многие разработчики на самом деле не знают, действительно ли Neo4j подойдет для их конкретных нужд; вот солидный обзор Stackoverflow, в котором обсуждается, зачем использовать Neo4j, а также плюсы и минусы.

2. Зависимости Maven

Начнем с объявления зависимостей Spring Data Neo4j в файле pom.xml. Упомянутые ниже модули Spring также необходимы для Spring Data Neo4j:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-neo4j</artifactId>
    <version>5.0.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.neo4j</groupId>
    <artifactId>neo4j-ogm-test</artifactId>
    <version>3.1.2</version>
    <scope>test</scope>
</dependency>

Эти зависимости также включают в себя необходимые модули для тестирования.

Обратите внимание, что последняя зависимость имеет область видимости «test». Но также обратите внимание, что при разработке приложений в реальном мире у вас, скорее всего, будет работать полноценный сервер Neo4J.

Если мы хотим использовать встроенный сервер, мы также должны добавить зависимость:

<dependency>
    <groupId>org.neo4j</groupId>
    <artifactId>neo4j-ogm-embedded-driver</artifactId>
    <version>3.1.2</version>
</dependency>

Зависимости spring-data-neo4j, neo4j-ogm-test и neo4j-ogm-embedded-driver доступны на Центральный Мейвен.

3. Конфигурация Neo4Jj

Конфигурация Neo4j очень прямолинейна и определяет параметры соединения для подключения приложения к серверу. Подобно большинству других модулей данных Spring, это конфигурация Spring, которую можно определить как конфигурацию XML или Java.

В этом руководстве мы будем использовать только конфигурацию на основе Java:

public static final String URL = 
  System.getenv("NEO4J_URL") != null ? 
  System.getenv("NEO4J_URL") : "http://neo4j:[email protected]:7474";

@Bean
public org.neo4j.ogm.config.Configuration getConfiguration() {
    return new Builder().uri(URL).build();
}

@Bean
public SessionFactory getSessionFactory() {
    return new SessionFactory(getConfiguration(), 
      "com.baeldung.spring.data.neo4j.domain");
}

@Bean
public Neo4jTransactionManager transactionManager() {
    return new Neo4jTransactionManager(getSessionFactory());
}

Как упоминалось выше, конфигурация проста и содержит только две настройки. Во-первых, SessionFactory ссылается на модели, которые мы создали для представления объектов данных. Затем свойства соединения с конечными точками сервера и учетными данными для доступа.

Neo4j выведет класс драйвера на основе протокола URI, в нашем случае «http».

Обратите внимание, что в этом примере свойства, связанные с подключением, настраиваются непосредственно на сервере; однако в рабочем приложении они должны быть должным образом экстернализованы и являться частью стандартной конфигурации проекта.

4. Репозитории Neo4j

В соответствии с инфраструктурой Spring Data, Neo4j поддерживает поведение абстракции репозитория Spring Data. Это означает, что доступ к базовому персистентному механизму абстрагируется во встроенном репозитории Neo4jRepository, где проект может напрямую расширять его и использовать предоставленные операции «из коробки».

Репозитории расширяемы с помощью аннотированных, именованных или производных методов поиска. Поддержка репозиториев Spring Data Neo4j также основана на Neo4jTemplate, поэтому базовая функциональность идентична.


4.1. Создание MovieRepository и PersonRepository

В этом руководстве мы используем два репозитория для сохранения данных:

@Repository
public interface MovieRepository extends Neo4jRepository<Movie, Long> {

    Movie findByTitle(@Param("title") String title);

    @Query("MATCH (m:Movie) WHERE m.title =~ ('(?i).*'+{title}+'.*') RETURN m")
    Collection<Movie> 
      findByTitleContaining(@Param("title") String title);

    @Query("MATCH (m:Movie)<-[:ACTED_IN]-(a:Person) 
      RETURN m.title as movie, collect(a.name) as cast LIMIT {limit}")
    List<Map<String,Object>> graph(@Param("limit") int limit);
}

Как вы можете, репозиторий содержит некоторые пользовательские операции, а также стандартные, унаследованные от базового класса.

Далее у нас есть более простой PersonRepository, в котором есть только стандартные операции:

@Repository
public interface PersonRepository extends Neo4jRepository <Person, Long> {
    //
}

Возможно, вы уже заметили, что PersonRepository — это просто стандартный интерфейс Spring Data. Это связано с тем, что в этом простом примере почти достаточно использовать встроенные операции, поскольку наш набор операций связан с сущностью Movie. Однако вы всегда можете добавить сюда пользовательские операции, которые могут заключать в себе одну или несколько встроенных операций.

4.2. Настройка Neo4jRepositories

В качестве следующего шага мы должны сообщить Spring о соответствующем репозитории, указав его в классе Neo4jConfiguration, созданном в разделе 3:

@Configuration
@ComponentScan("com.baeldung.spring.data.neo4j")
@EnableNeo4jRepositories(
  basePackages = "com.baeldung.spring.data.neo4j.repository")
public class MovieDatabaseNeo4jConfiguration {
    //
}

5. Полная модель данных

Мы уже начали рассматривать модель данных, поэтому давайте теперь все это выложим — полный Фильм, Роль и Человек. Сущность Person ссылается на сущность Movie через отношение Role.

@NodeEntity
public class Movie {

    @Id @GeneratedValue
    Long id;

    private String title;

    private int released;

    private String tagline;

    @Relationship(type="ACTED_IN", direction = Relationship.INCOMING)

    private List<Role> roles;

    // standard constructor, getters and setters 
}

Обратите внимание, что мы аннотировали Movie с помощью @NodeEntity, чтобы указать, что этот класс напрямую сопоставлен с узлом в Neo4j.

@JsonIdentityInfo(generator=JSOGGenerator.class)
@NodeEntity
public class Person {

    @Id @GeneratedValue
    Long id;

    private String name;

    private int born;

    @Relationship(type = "ACTED_IN")
    private List<Movie> movies;

    // standard constructor, getters and setters 
}

@JsonIdentityInfo(generator=JSOGGenerator.class)
@RelationshipEntity(type = "ACTED_IN")
public class Role {

    @Id @GeneratedValue
    Long id;

    private Collection<String> roles;

    @StartNode
    private Person person;

    @EndNode
    private Movie movie;

    // standard constructor, getters and setters 
}

«

«Конечно, эти последние два класса аннотированы аналогичным образом, а ссылка -movies-связывает класс Person с Movie отношением ACTED_IN.

6. Доступ к данным с помощью MovieRepository

6.1. Сохранение нового объекта фильма

Movie italianJob = new Movie();
italianJob.setTitle("The Italian Job");
italianJob.setReleased(1999);
movieRepository.save(italianJob);

Person mark = new Person();
mark.setName("Mark Wahlberg");
personRepository.save(mark);

Role charlie = new Role();
charlie.setMovie(italianJob);
charlie.setPerson(mark);
Collection<String> roleNames = new HashSet();
roleNames.add("Charlie Croker");
charlie.setRoles(roleNames);
List<Role> roles = new ArrayList();
roles.add(charlie);
italianJob.setRoles(roles);
movieRepository.save(italianJob);

6.2. Retrieving an Existing Movie Object by Title

Let’s now verify the inserted movie by retrieving it using the defined title which is a custom operation:

Movie result = movieRepository.findByTitle(title);

6.3. Retrieving an Existing Movie Object by a Part of the Title

It is possible to search to search an existing movie using a part of the title:

Collection<Movie> result = movieRepository.findByTitleContaining("Italian");

6.4. Retrieving All the Movies

All the movies can be retrieve once and can be check for the correct count:

Collection<Movie> result = (Collection<Movie>) movieRepository.findAll();

However there are number of find methods provided with default behavior which is useful for customs requirements and not all are described here.

6.5. Count the Existing Movie Objects

After inserting several movie objects, we can get exiting movie count:

long movieCount = movieRepository.count();

6.6. Deleting an Existing Movie

movieRepository.delete(movieRepository.findByTitle("The Italian Job"));

After deleting the inserted movie, we can search for the movie object and verify the result is null:

assertNull(movieRepository.findByTitle("The Italian Job"));

6.7. Delete All Inserted Data

It is possible to delete all the elements in the database making the database empty:

movieRepository.deleteAll();

The result of this operation quickly removes all data from a table.

7. Conclusion

In this tutorial, we went through the basics of Spring Data Neo4j using a very simple example.

However Neo4j is capable of catering to very advanced and complex applications having a huge set of relations and networks. And Spring Data Neo4j also offers advanced features to map annotated entity classes to the Neo4j Graph Database.

Давайте сохраним некоторые данные — сначала новый фильм, затем человека и, конечно же, роль — включая все имеющиеся у нас данные отношений: