Перейти к основному содержимому

Введение в Spring Data Neo4j

· 6 мин. чтения

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>

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

Обратите внимание, что последняя зависимость имеет область действия «тест». Но также обратите внимание, что при разработке приложений в реальном мире у вас, скорее всего, будет работать полноценный сервер 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 доступны на Maven Central.

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

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

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

public static final String URL = 
System.getenv("NEO4J_URL") != null ?
System.getenv("NEO4J_URL") : "http://neo4j:movies@localhost:7474";

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

@Bean
public SessionFactory getSessionFactory() {
return new SessionFactory(getConfiguration(),
"com.foreach.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. Настройка репозиториев Neo4j

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

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

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

Мы уже начали рассматривать модель данных, так что давайте теперь все это выложим — полное Movie, Role и Person . Сущность 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. Получение существующего объекта фильма по заголовку

Давайте теперь проверим вставленный фильм, извлекая его с помощью определенного заголовка, который является пользовательской операцией:

Movie result = movieRepository.findByTitle(title);

6.3. Извлечение существующего кинообъекта по части заголовка

Возможен поиск для поиска существующего фильма по части названия:

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

6.4. Получение всех фильмов

Все фильмы можно получить один раз и проверить правильность подсчета:

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

Однако существует ряд методов поиска с поведением по умолчанию, которые полезны для таможенных требований, и не все они описаны здесь.

6.5. Подсчитайте существующие кинообъекты

После вставки нескольких объектов фильма мы можем получить количество выходящих фильмов:

long movieCount = movieRepository.count();

6.6. Удаление существующего фильма

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

После удаления вставленного фильма мы можем найти объект фильма и убедиться, что результат равен нулю:

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

6.7. Удалить все вставленные данные

Можно удалить все элементы в базе данных, сделав базу данных пустой:

movieRepository.deleteAll();

Результат этой операции быстро удаляет все данные из таблицы.

7. Заключение

В этом уроке мы рассмотрели основы Spring Data Neo4j на очень простом примере.

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

Реализацию приведенных выше фрагментов кода и примеры можно найти в проекте GitHub — это проект на основе Maven, поэтому его легко импортировать и запускать как есть.