Аналитика больших данных с Neo4j и Java, часть 2

Большие данные

этой статьипервая частьВведение в Neo4j и его язык запросов Cypher. Если вы читали часть 1, то поняли, почему Neo4j и другие графовые базы данных особенно популярны.

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

Затем мы используем язык запросов Cypher для моделирования семьи в Neo4j, включая личные атрибуты, такие как возраст, пол и отношения между членами семьи. Мы создаем несколько друзей, чтобы расширить наш социальный граф, затем добавляем пары ключ/значение, чтобы создать список фильмов, просмотренных каждым пользователем. Наконец, мы запросили наши данные, используя графическую аналитику, чтобы найти фильм, который пользователь не видел, но может ему понравиться.

Язык запросов Cypher отличается от традиционных языков запросов данных, таких как SQL. Вместо того, чтобы думать о таких вещах, как таблицы и отношения внешних ключей, Cypher заставляет вас думать об узлах, естественных отношениях между узлами и различных обходах, которые могут быть выполнены между отдельными отношениями. С помощью Cypher вы можете создать собственную ментальную модель того, как объекты реального мира связаны друг с другом. Требуется некоторая практика, чтобы научиться писать запросы Cypher, но как только вы поймете, как они работают, даже очень сложные запросы обретут смысл.

После моделирования социального графа в Neo4j с использованием языка запросов Cypher и написания запросов с использованием этого социального графа очень просто написать код Java для выполнения запроса на графе. В этой статье вы узнаете, как интегрировать Neo4j с клиентским веб-приложением Java, которое вы можете использовать для запроса социального графа, созданного нами в части 1.

Настройте свой проект Neo4j

Наш первый шаг — создать новый проект Maven:

mvn archetype:generate -DgroupId=com.geekcap.javaworld -DartifactId=neo4j-example -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Откройте свойpom.xmlфайл и добавьте драйвер Neo4j версии 1.4.1 на момент написания:

       <dependency>
            <groupId>org.neo4j.driver</groupId>
            <artifactId>neo4j-java-driver</artifactId>
            <version>1.4.1</version>
        </dependency>    

Создайте драйвер Neo4j

Затем создайте Neo4jDriver,Следующее:

Driver driver = GraphDatabase.driver( "bolt://localhost:7687", AuthTokens.basic("neo4j", "neo4j"));

КнигаGraphDatabaseКласс имеет метод, называемый статическимdriver()принимает URL-адрес для подключения к Neo4j иAuthToken. Вы можете создать базовуюAuthToken.

существуетDriverОблегченное общение с Neo4j. мы запрашиваемDriverСоздайтеSessionобъект для выполнения запроса следующим образом:

Session session = driver.session();

Интерфейс сеанса

Долженorg.neo4j.driver.v1.SessionИнтерфейс для выполнения транзакций на Neo4j. В простейшей форме мы можем выполнить унаследованное отrun()метод. Затем будет запущена транзакция, будет запущен наш оператор, и транзакция будет зафиксирована.Sessionorg.neo4j.driver.v1.StatementRunnerSession

ДолженStatementRunnerНесколько вариантов, определяемых интерфейсомrun()метод. Это тот, который мы будем использовать:

StatementResult run(String statementTemplate, Map<String,Object> statementParameters)

объявить параметры

ДолженstatementTemplateэто файл, содержащий наш запрос CypherString,statementParametersВключите именованные параметры, которые мы будем использовать. Например, мы можем захотеть создатьPerson:

session.run("CREATE (person: Person {name: {name}, age: {age}})",
parameters("name", person.getName(), "age", person.getAge()));

{name}和{age}named, который можно решить, передав какStringстоило тогоMap. каждыйStringОба содержат имя свойства и должны соответствовать значению в шаблоне. Долженparametersметод обычно начинается сValuesСтатический импорт объекта:

import static org.neo4j.driver.v1.Values.parameters

Управление транзакциями

ОдинSessionПосле того, как это было сделано, вам нужно вызвать его с помощьюclose()способ закрыть. Для удобства,Sessionобъект реализуетjava.lang.AutoCloseableинтерфейс, поэтому, начиная с Java 7, вы можете сделать это в операторе try-with-resources, например:

try (Session session = driver.session()) {
    session.run("CREATE (person: Person {name: {name}, age: {age}})",
    parameters("name", person.getName(), "age", person.getAge()));
}

Наконец, если вы выполняете несколько операторов, связанных с одной транзакцией, вы можете обойтиSessionизrun()Методы автоматизированного управления транзакциями и прозрачные самоуправляемые транзакции. Например:

try (Session session = driver.session()) {
    try (Transaction tx = session.beginTransaction()) {
        tx.run("CREATE (person: Person {name: {name}, age: {age}})",
                parameters("name", person.getName(), "age", person.getAge()));
        tx.success();
    }
}

звонокSession.beginTransaction()вернутьTransactionОбъект, который можно использовать для запуска операторов Cypher. После выполнения оператора Cypher вы должны вызватьtx.success()или оператор try-with-resources отменит транзакцию. ДолженTransactionвыполнитьAutoCloseable. Если транзакция помечена как успешная (вызовомsuccess()), транзакция зафиксирована, в противном случае транзакция будет отменена. Вы можете сделать это, позвонивTransactionизfailure()способ явного отказа транзакции.

объект записи

вы могли наблюдатьSessionа такжеTransactionв классеrun()методы возвращаютStatementResultпример.StatementResultинтерфейс доступенRecordсписок,RecordОбъекты могут иметь один или несколькоValueобъект.

с JDBC отResultSetПолученное значение аналогично,RecordПозволяет получить значения по индексу или по имени. вернутьValueобъект может быть вызванNode.asNode()методы или примитивы (например,Stringили целое число), вызывая другиеasXXX()Один из методов конвертирует в Neo4j. Примеры в предыдущих разделах в основном возвращают узлы, но в последнем примере имя человека принимается какStringвернуть. Вот почемуValueОбъекты Reason обеспечивают гибкость в возвращаемых типах.

Пример приложения на Java

Теперь мы возьмем то, что мы узнали, и создадим пример приложения на Java. на основеПримеры моделирования и запросов в части 1, это приложение создаетPersonобъект, найти всеPersonобъект, найти всех друзейPerson, и найтиPersonВсе фильмы, которые вы видели.

Листинг 1 и Листинг 2 создают определенияPersonи класс Java дляMovie. В листинге 3 показан исходный код нашего тестового класса:Neo4jClient.

Листинг 1. Person.java

package com.geekcap.javaworld.neo4j.model;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Листинг 2. Movie.java

package com.geekcap.javaworld.neo4j.model;

public class Movie {
    private String title;
    private int rating;

    public Movie() {
    }

    public Movie(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getRating() {
        return rating;
    }

    public void setRating(int rating) {
        this.rating = rating;
    }
}

Листинг 3. Neo4jClient.java

package com.geekcap.javaworld.neo4j;

import com.geekcap.javaworld.neo4j.model.Movie;
import com.geekcap.javaworld.neo4j.model.Person;
import org.neo4j.driver.v1.*;
import org.neo4j.driver.v1.types.Node;

import java.util.HashSet;
import java.util.Set;

import static org.neo4j.driver.v1.Values.parameters;

public class Neo4jClient {

    /**
     * Neo4j Driver, used to create a session that can execute Cypher queries
     */
    private Driver driver;

    /**
     * Create a new Neo4jClient. Initializes the Neo4j Driver.
     */
    public Neo4jClient() {
        // Create the Neo4j driver
        driver = GraphDatabase.driver( "bolt://localhost:7687", AuthTokens.basic("neo4j", "neo4j"));
    }

    /**
     * Create a new Person.
     * @param person    The Person to create
     */
    public void createPerson(Person person) {
        // Create a Neo4j session. Because the Session object is AutoCloseable, we can use a try-with-resources statement
        try (Session session = driver.session()) {

            // Execute our create Cypher query
            session.run("CREATE (person: Person {name: {name}, age: {age}})",
                    parameters("name", person.getName(), "age", person.getAge()));
        }
    }

    /**
     * Finds all Person objects in the Neo4j database.
     * @return  A set of all Person objects in the Neo4j database.
     */
    public Set<Person> findAllPeople() {
        // Create a set to hold our people
        Set<Person> people = new HashSet<>();

        // Create a Neo4j session
        try (Session session = driver.session()) {

            // Execute our query for all Person nodes
            StatementResult result = session.run("MATCH(person:Person) RETURN person");

            // Iterate over the response
            for (Record record: result.list()) {
                // Load the Neo4j node from the record by the name "person", from our RETURN statement above
                Node person = record.get("person").asNode();

                // Build a new person object and add it to our result set
                Person p = new Person();
                p.setName(person.get("name").asString());
                if (person.containsKey("age")) {
                    p.setAge(person.get("age").asInt());
                }
                people.add(p);
            }
        }

        // Return the set of people
        return people;
    }

    /**
     * Returns the friends of the requested person.
     *
     * @param person    The person for which to retrieve all friends
     * @return          A Set that contains all Person objects for which there is a FRIEND relationship from
     *                  the specified person
     */
    public Set<Person> findFriends(Person person) {
        // A Set to hold our response
        Set<Person> friends = new HashSet<>();

        // Create a session to Neo4j
        try (Session session = driver.session()) {
            // Execute our query
            StatementResult result = session.run("MATCH (person: Person {name: {name}})-[:FRIEND]-(friend: Person) RETURN friend",
                    parameters("name", person.getName()));

            // Iterate over our response
            for (Record record: result.list()) {

                // Create a Person
                Node node = record.get("friend").asNode();
                Person friend = new Person(node.get("name").asString());

                // Add the person to the friend set
                friends.add(friend);
            }
        }

        // Return the set of friends
        return friends;
    }

    /**
     * Find all movies (with rating) seen by the specified Person.
     *
     * @param person    The Person for which to find movies seen
     * @return          A Set of Movies (with ratings)
     */
    public Set<Movie> findMoviesSeenBy(Person person) {
        Set<Movie> movies = new HashSet<>();
        try (Session session = driver.session()) {
            // Execute our query
            StatementResult result = session.run("MATCH (person: Person {name: {name}})-[hasSeen:HAS_SEEN]-(movie:Movie) RETURN movie.title, hasSeen.rating",
                    parameters("name", person.getName()));

            // Iterate over our response
            for (Record record: result.list()) {

                Movie movie = new Movie(record.get("movie.title").asString());
                movie.setRating(record.get("hasSeen.rating").asInt());
                movies.add(movie);
            }
        }
        return movies;
    }

    /**
     * Helper method that prints a person set to the standard output.
     * @param people    The set of Person objects to print to the standard output
     */
    public static void printPersonSet(Set<Person> people) {
        for (Person person: people) {
            StringBuilder sb = new StringBuilder("Person: ");
            sb.append(person.getName());
            if (person.getAge()>0) {
                sb.append(" is " + person.getAge() + " years old");
            }
            System.out.println(sb);
        }
    }


    /**
     * Test methods
     */
    public static void main(String ... args) {
        Neo4jClient client = new Neo4jClient();
        client.createPerson(new Person("Duke", 22));

        Set<Person> people = client.findAllPeople();
        System.out.println("ALL PEOPLE");
        printPersonSet(people);

        Set<Person> friendsOfMichael = client.findFriends(new Person("Michael"));
        System.out.println("FRIENDS OF MICHAEL");
        printPersonSet(friendsOfMichael);

        Set<Movie> moviesSeenByMichael = client.findMoviesSeenBy(new Person("Michael"));
        System.out.println("MOVIES MICHAEL HAS SEEN:");
        for (Movie movie: moviesSeenByMichael) {
            System.out.println("Michael gave the movie " + movie.getTitle() + " a rating of " + movie.getRating());
        }
    }
}

Пример приложения: клиентский класс Neo4j

существуетNeo4jClientNeo4j класс создан в его конструкцииDriver. затем его метод использованияDriverсоздатьSessionобъект для выполнения запросов Cypher.createPerson()Метод выполняет запрос Cypher с именованными параметрами «имя» и «возраст».CREATE (person:Person {...}).parameters()метод связывает эти параметры с указаннымPersonатрибуты имени и возраста.

findAllPeople()поиск методаPersonВсе объекты в базе. Обратите внимание, что этот метод возвращаетвсе, поэтому, если у вас много людей, вы можете добавить к ответуLIMIT. Вот пример:

MATCH (person:Person) RETURN person LIMIT 25

В этом случае мы возвращаем полныйPersonузел, поэтому я начинаю сRecordполучить "человек" и использоватьNodedизasNode()метод преобразования.

findFriends()метод делает то же самое, но выполняет другой запрос Cypher:

MATCH (person: Person {name: {name}})-[:FRIEND]-(friend: Person) RETURN friend

Мы спрашиваем человека с данным именем и ищем этого человекаFRIENDотношения, найти всеPersonУзлы, назовите каждый узел «друзьями». Поэтому, когда мы начинаем сRecordПри получении ответа в , мы запрашиваем «друзья» и преобразуем его вNode.

Наконец,findMoviesSeenBy()Метод выполняет следующий запрос Cypher:

MATCH (person: Person {name: {name}})-[hasSeen:HAS_SEEN]-(movie:Movie) RETURN movie.title, hasSeen.rating

Этот запрос начинается с назначенного лица и следуетHAS_SEENа такжеMovieВсе отношения узла. Затем он возвращает атрибут названия фильмаmovie.titleи оценивается какhasSeen.rating.

Чтобы сделать это, мы должныHAS_SEENУкажите имя переменной в отношенииhasSeen. Поскольку мы запрашиваем названия фильмов и рейтинги, мы получаем из следующихRecord::

record.get("movie.title").asString()
record.get("hasSeen.rating").asInt()

Долженmain()метод создания новогоNeo4jClient, создайте 22-летнего человека по имени «Герцог» (подсказка: точно так же, как Java)Person. Он находит друзей Майкла и фильмы, которые он видел.

В листинге 4 показан Mavenpom.xmlфайл, который мы используем для сборки и запуска нашего приложения.

Листинг 4. Maven POM для приложения Neo4jClient

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.geekcap.javaworld</groupId>
    <artifactId>neo4j-example</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>neo4j-example</name>
    <url>http://maven.apache.org</url>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Import Neo4j -->
        <dependency>
            <groupId>org.neo4j.driver</groupId>
            <artifactId>neo4j-java-driver</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>com.geekcap.javaworld.neo4j.Neo4jClient</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>install</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Этот файл pom.xml импортируетneo4j-java-driverзависимости, затем определите три плагина:

  • maven-compiler-pluginУстановите версию сборки Java на 1.8.
  • maven-jar-pluginСделайте основной класс установленным в исполняемый файл JAR,com.geekcap.javaworld.neo4j.Neo4jClientи содержитlibВсе файлы в каталоге файлов JARCLASSPATH.
  • maven-dependency-plugin будетСкопируйте все зависимости в каталог сборки проекта.libпапка.

Создайте и запустите клиентское приложение Neo4j.

Теперь вы можете создать клиентское приложение Neo4j с помощью:

mvn clean install

ты сможешьtargetЗапустите его из каталога с помощью:

java -jar neo4j-example-1.0-SNAPSHOT.jar

Вы должны увидеть вывод, подобный следующему:

ALL PEOPLE
Person: Steven is 45 years old
Person: Jordyn
Person: Michael is 16 years old
Person: Katie
Person: Koby
Person: Duke is 22 years old
Person: Grant
Person: Rebecca is 7 years old
Person: Linda
Person: Charlie is 16 years old
FRIENDS OF MICHAEL
Person: Charlie
Person: Grant
Person: Koby
MOVIES MICHAEL HAS SEEN:
Michael gave movie Avengers a rating of 5

Обязательно перейдите в веб-интерфейс Neo4j и выполните несколько запросов! Вы должны увидеть, как Duke создан, и сможете проверить результат.

Заключение части 2

Neo4j — это графовая база данных для управления тесно связанными данными. Мы начали это исследование с рассмотрения требований к графовым базам данных, особенно при запросе более чем трех степеней разделения в отношениях. После настройки Neo4j в нашей среде разработки мы потратили большую часть времени на изучение языка запросов Neo4j Cypher. Мы построили сеть семейных отношений и запросили эти отношения с помощью Cypher. В этой статье мы сосредоточимся на том, чтобы научиться

Думайте графически
. В этом сила Neo4j и самая сложная функция, которой овладевает большинство разработчиков.

Во второй части вы узнали, как написать приложение Java, которое подключается к Neo4j и выполняет запросы Cypher. Мы выбрали самый простой (ручной) способ интеграции Java с Neo4j. После того, как вы освоите основы, вы, возможно, захотите изучитьИнтеграция Java с Neo4jБолее продвинутые подходы, такие как использование библиотеки Neo4j Object Graph Mapping (OGM), Neo4j-OGM и Spring Data.

Английский оригинал: https://www.javaworld.com/article/3269575/big-data-analytics-with-neo4j-and-java-part-2.html

Для получения дополнительных статей, пожалуйста, посетите: http://www.apexyun.com

Общедоступный номер: Galaxy № 1

Контактный адрес электронной почты: public@space-explore.com

(Пожалуйста, не перепечатывайте без разрешения)