Статьи

Использование Spring Data Neo4j для построения систем рекомендаций

Сегодня мы хотели бы познакомить вас с Spring Data Neo4j . Для этого мы реализовали небольшое демонстрационное приложение. Контекст витрины представляет собой систему магазинов. Поэтому было бы полезно подсчитать, что также просматривали другие пользователи — как это известно по многим популярным интернет-магазинам, например Amazon. Поскольку эти связи между пользователями и продуктами легко отображаются в виде графика, мы решили использовать Neo4j для представления узлов и отношений между ними.

Что такое Spring Data Neo4j?

Прежде всего, что такое Spring Data ? Это проект SpringSource, целью которого является предоставление модели программирования и соглашений Spring для баз данных NoSQL. Spring Data поддерживает различные базы данных NoSQL, такие как Redis, Riak, MongoDB и другие. Он также обеспечивает уровень абстракции для реализаций сокращения карт, таких как Hadoop.

С 2010 года существует инициатива Spring Data Neo4j . Некоторые ресурсы можно найти на сайте Neo4j . На данный момент лучшим путеводителем является «Хорошие отношения», написанные Майклом Хангером, ведущим разработчиком этого проекта. Это бесплатно для скачивания, а также доступно в виде HTML-версии . Некоторые примеры кода Spring Data Neo4j находятся в Git-репозитории Spring Data Neo4j . Существует также книга О’Рейли о Spring Data Neo4j .

Почему бы не использовать Core Neo4j?

Конечно, также можно было бы просто использовать ядро ​​Neo4j или создать собственную интеграцию. Но если у вас есть опыт работы с другими весенними проектами, вы определите преимущества. Как инженер-программист в целом, вы не хотите заботиться о технических деталях, таких как сопоставление сущностей или управление транзакциями. Вы просто должны знать концепцию, и Spring обрабатывает магию на заднем плане. Это сравнимо с поддержкой Hibernate в Spring:

  • Common Spring и Spring Data инфраструктура. Neo4j очень легко встроить в существующие приложения, управляемые средой Spring.
  • Аннотации для объявления узлов и их связей.
  • Код гораздо проще понять.
  • Состояние объекта поддерживается базой данных графа.
  • Поддержка сервера Neo4j.

Как использовать Spring Data Neo4j ?

Если вы используете Maven, вы можете включить Spring Data Neo4j в ваш проект, добавив его в ваш pom.xml (помимо зависимостей для Spring и Neo4j):

<!-- Spring Data Neo4j -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-neo4j</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>

Настройка Neo4j выполняется в следующем весеннем контексте:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd">

    <context:spring-configured/>
    <context:annotation-config/>

    <neo4j:config storeDirectory="target/data/db"/>

    <neo4j:repositories base-package="com.comsysto.neo4j.showcase"/>
</beans>

Свойство «storeDirectory» конфигурации Neo4j может быть папкой на ваш выбор. База данных Neo4j будет храниться там локально. После этого вы можете приступить к реализации ваших узлов и сущностей отношений, представляющих вашу графовую модель.

Как объявить сущности узла?

Для узловых сущностей создайте новый класс, похожий на этот:

@NodeEntity
 public class Product {

@GraphId
 private Long graphId;

@Indexed(unique = true)
 private String productId;
@Indexed(indexType = IndexType.FULLTEXT, indexName = "productName")
 private String productName;
@RelatedToVia(type = RelationshipTypes.RECOMMEND)
 private Set<RecommendRelationship> productsRecommendRelationships = new HashSet<RecommendRelationship>();

public Product() {/* NOOP */}

public Product(String productId, String productName) {
 this.productId = productId;
 this.productName = productName;
}

// all getters and setters (for graphId only getter)
...

// further methods 
...

// @Override methods like toString(), equals(Object o), hashCode()
...

Методы получения и установки необходимы для доступа к свойству в среде Spring. Вы также можете реализовать свои собственные дополнительные методы. Но типичный объект Neo4j — это классический JavaBean, состоящий из свойств и их методов доступа. Также рекомендуется реализовать equals и hashCode, так как в некоторых случаях Spring Data Neo4j сравнивает объекты для сопоставления сущностей и отношений.

Как создать отношения между сущностями узла?

Spring Data может обрабатывать отношения между узлами тремя различными способами. То, какую возможность вы выберете, зависит от двух аспектов: типа отношений, которые необходимо смоделировать (1: 1 против 1: n), и от того, простые это отношения или богатые. Богатые отношения имеют дополнительные атрибуты.

Отношения 1: 1 очень просты: дочерний узел должен просто ссылаться на родительский узел как свойство (методы доступа должны быть реализованы). Там нет аннотации требуется. Spring Data справляется со всей магией.

В простых отношениях 1: n вы должны добавить набор, содержащий дочерние узлы в родительском узле (см. Выше). В дополнение к этому вы должны аннотировать этот набор с помощью @RelatedTo (type = «relationsType») следующим образом:

@NodeEntity
public class Product extends IdentifiableEntity {

    @RelatedTo(type = "buyer")
    Set<Customer> customers;

    //getters and setters, equals and hashCode
}

Богатые отношения демонстрируют всю мощь Spring Data в графовой модели Вы можете моделировать отношения реального мира с дополнительными атрибутами. Для этого вам нужно создать объект отношения, хранящий свойства отношения. Кроме того, родительский и дочерний узлы должны быть указаны аннотациями (@StartNode, @EndNode). Следующий пример демонстрирует это:

@NodeEntity
public class User extends IdentifiableEntity {

    @RelatedToVia(type = "clickProductsRelationship")
    Set<ClickedProductRelationship> clickedProducts;
}

@RelationshipEntity(type = "clickProductsRelationship")
public class ClickedProductRelationship {

    @StartNode
    @Fetch
    Product start;

    @EndNode
    @Fetch
    Product end;

    int clicksCount;

    //getters and setters, equals and hashCode
}

Позаботьтесь о свойстве @Fetch. Во многих случаях не все связанные объекты «один ко многим» должны быть доступны после загрузки указанной сущности. Поведение Spring Data по умолчанию только для получения списка идентификаторов, идентифицирующих связанные объекты, когда объект узла загружен. Этот подход сопоставим с механизмом отложенной загрузки, известным из многих других сред, таких как Hibernate. Чтобы предотвратить это, вы можете добавить аннотацию @Fetch к соответствующей сущности узла.

В целом, хорошей практикой является определение типов отношений как констант в отдельном классе, так как эти строки будут использоваться в разных фрагментах кода в разных классах. Наша графовая модель имеет два типа отношений между узлами. Класс выглядит так:

public final class RelationshipTypes {
    public static final String CLICKED = "CLICKED";
    public static final String RECOMMEND = "RECOMMEND";
}

Как загрузить узлы-узлы и соответствующие им отношения?

Чтобы получить доступ к сущностям и отношениям узлов, мы должны создать наш собственный интерфейс, расширяющий интерфейс GraphRepository в Spring. Это выглядит так:

public interface ProductRepository extends GraphRepository<Product> {

    Product findByProductId(String productId);

    List<Product> findByProductNameLike(String productName);

    @Query("START product=node(*) " +
            "WHERE HAS (product.productName)" +
            "RETURN product " +
            "ORDER BY product.productName")
    List<Product> findAllProductsSortedByName();

    @Query("START product=node:Product(productId={productId}) " +
            "MATCH product-[recommend:RECOMMEND]->otherProduct " +
            "RETURN otherProduct " +
            "ORDER BY recommend.count DESC " +
            "LIMIT 5 ")
    List<Product> findOtherUsersAlsoViewedProducts(@Param("productId") String productId);

    // more queries here
    ...
}

Как вы можете видеть из кода, репозиторий графов — это интерфейс, который определяет только имена функций, возвращаемые значения и запрос Cypher (если требуется). Это очень удобно, так как фреймворк не нуждается в соответствующей реализации. На основе описанных выше параметров и родительского интерфейса «GraphRepository» Spring Data может создавать прокси-объекты, взаимодействующие с базовым API Neo4j.
Для более подробной информации о возможностях, посмотрите документацию репозитория . Если вы не знакомы с Cypher, посмотрите этот учебник Cypher . Тем не менее, возможно, что вам понадобится индивидуальная реализация вашего GraphRepository. В этом случае вы можете написать класс, который реализует интерфейс.

Каковы ограничения Spring Data Neo4j ?

Во время подготовки этой статьи мы обнаружили некоторые ограничения Spring Data Neo4j:

  • В настоящее время невозможно выполнить запросы Cypher, содержащие DISTINCT и ORDER BY в одном запросе.
  • Если у вас есть какие-то трудно угадываемые проблемы, сообщения регистрации не очень интуитивны.

О чем наша демка?

Демонстрация показывает часть репозитория графиков системы магазина, в которой представлены продукты, которые также просматривали другие пользователи. Например, если пользователи, посетившие страницу «Пицца Вегетарианец», впоследствии просматривали страницу «Пицца Рустика», поскольку искали вегетарианскую пиццу, другим пользователям также может быть полезно взглянуть на «Пицца Рустика». ».

Некоторые тестовые случаи можно найти в классе SpringDataNeo4jProductUserTest .

Что вам нужно для запуска этой демонстрации самостоятельно?

Для запуска демоверсии вам необходимо установить Maven на вашем компьютере. Если вы не знакомы с Maven, прочитайте эту статью о том, как запустить Maven .

Код доступен на github: https://github.com/comsysto/spring-data-neo4j-showcase

Что может помочь, если у вас есть проблемы?

Когда мы готовили эту демонстрацию, мы столкнулись с некоторыми проблемами, с которыми вы можете столкнуться:

  • Будьте осторожны с индексами. Если вы используете идентификаторы, они должны быть объявлены как уникальные, как в коде выше.
  • Если вы хотите, чтобы отношения имели атрибуты, используйте @RelatedToVia.
  • Инициализируйте все Наборы, например, с помощью HashSet, как в коде выше.
  • Не используйте graphId в качестве идентификатора. GraphIds из удаленных узлов могут быть повторно использованы Neo4j и представляют другой объект после удаления первого.
  • Используйте @Fetch для начала и конца узла отношений. В противном случае они не будут выбраны, если объект загружен.
  • Не изменяйте геттеры и сеттеры, так как они используются каркасом для сохранения значений. Используйте дополнительные методы для этого.
  • Запускайте запросы Cypher с помощью простого оператора и расширяйте его, пока не получите желаемое.
  • Позаботьтесь о экранировании строк в запросах Cypher. Экранирование строк в ядре API Neo4j отличается от этого в Spring Data.

Как продлить демонстрацию?

Вы можете расширить эту демонстрацию, как пожелаете. Например, вы можете добавить больше полей к объектам узла и расширить их значениями для дальнейших рекомендаций.

Любые вопросы?

Если у вас есть какие-либо отзывы, пожалуйста, пишите на  [email protected] или [email protected] !

Где вы можете узнать больше о Neo4j?

Мы предлагаем учебник Neo4j, который состоится в нашем головном офисе 14 ноября. Второй будет 17 декабря. Это руководство охватывает основные функции графической базы данных Neo4j. Сочетая теоретические и практические занятия, участники быстро узнают, как легко разработать приложение на основе Neo4j. Для получения дополнительной информации, пожалуйста, загляните на нашу страницу событий . Если вы хотите зарегистрироваться на ноябрьский урок, перейдите по этой ссылке на eventbrite ! С промо-кодом «JUGM20» вы можете получить скидку 20%.