Руководство по Neo4J с Java
1. Вступление
Эта статья посвященаNeo4j - одной из самых зрелых и полнофункциональных графических баз данных на рынке сегодня. Графические базы данных подходят к задаче моделирования данных с точки зрения того, что многие вещи в жизни поддаются представлению в виде набораnodes (V) и связей между ними, называемыхedges (E).
2. Встроенный Neo4j
Самый простой способ начать работу сNeo4j - использовать встроенную версию, в которойNeo4j работает в той же JVM, что и ваше приложение.
Во-первых, нам нужно добавить зависимость Maven:
org.neo4j
neo4j
3.4.6
Вы можете проверитьthis link, чтобы загрузить последнюю версию.
Затем давайте создадим фабрику:
GraphDatabaseFactory graphDbFactory = new GraphDatabaseFactory();
Наконец, мы создаем встроенную базу данных:
GraphDatabaseService graphDb = graphDbFactory.newEmbeddedDatabase(
new File("data/cars"));
Теперь реальные действия могут начаться! Во-первых, нам нужно создать несколько узлов в нашем графе, и для этого нам нужно запустить транзакцию, посколькуNeo4j отклонит любую деструктивную операцию, если транзакция не была запущена:
graphDb.beginTx();
Как только мы осуществим транзакцию, мы можем начать добавлять узлы:
Node car = graphDb.createNode(Label.label("Car"));
car.setProperty("make", "tesla");
car.setProperty("model", "model3");
Node owner = graphDb.createNode(Label.label("Person"));
owner.setProperty("firstName", "example");
owner.setProperty("lastName", "example");
Здесь мы добавили узелCar со свойствамиmake иmodel, а также узелPerson со свойствамиfirstName иlastName
Теперь мы можем добавить отношения:
owner.createRelationshipTo(car, RelationshipType.withName("owner"));
В приведенном выше заявлении добавлено ребро, соединяющее два узла с меткойowner. Мы можем проверить эту взаимосвязь, выполнив запрос, написанный на мощном языкеNeo4j’sCypher:
Result result = graphDb.execute(
"MATCH (c:Car) <-[owner]- (p:Person) " +
"WHERE c.make = 'tesla'" +
"RETURN p.firstName, p.lastName");
Здесь мы просим найти владельца автомобиля для любого автомобиля, марка которого является tesla и вернуть нам его / ее firstName и lastName. Неудивительно, что это возвращает:\{p.firstName=example, p.lastName=example}
3. Cypher Query Language
Neo4j предоставляет очень мощный и довольно интуитивно понятный язык запросов, который поддерживает полный набор функций, которые можно ожидать от базы данных. Давайте рассмотрим, как мы можем выполнить эти стандартные задачи создания, извлечения, обновления и удаления.
3.1. Создать узел
Ключевое слово Create может использоваться для создания как узлов, так и отношений.
CREATE (self:Company {name:"example"})
RETURN self
Здесь мы создали компанию с единственным свойствомname. Определение узла помечено круглыми скобками, а его свойства заключены в фигурные скобки. В этом случаеself - это псевдоним для узла, аCompany - это метка узла.
3.2. Создать отношения
Можно создать узел и связь с этим узлом в одном запросе:
Result result = graphDb.execute(
"CREATE (example:Company {name:\"example\"}) " +
"-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" +
"RETURN example, tesla");
Здесь мы создали узлыexample иtesla и установили между ними отношения собственности. Создание связей с уже существующими узлами, конечно, также возможно.
3.3. Получить данные
Ключевое словоMATCH используется для поиска данных в сочетании сRETURN для управления возвращаемыми точками данных. ПредложениеWHERE можно использовать для фильтрации только тех узлов, которые имеют желаемые свойства.
Давайте выясним название компании, которая владеет Tesla Model X:
Result result = graphDb.execute(
"MATCH (company:Company)-[:owns]-> (car:Car)" +
"WHERE car.make='tesla' and car.model='modelX'" +
"RETURN company.name");
3.4. Обновить узлы
Ключевое словоSET может использоваться для обновления свойств или меток узла. Давайте добавим пробег к нашему Tesla:
Result result = graphDb.execute("MATCH (car:Car)" +
"WHERE car.make='tesla'" +
" SET car.milage=120" +
" SET car :Car:Electro" +
" SET car.model=NULL" +
" RETURN car");
Здесь мы добавляем новое свойство с именемmilage, изменяем метки какCar иElectro, и, наконец, полностью удаляем свойствоmodel.
3.5. Удалить узлы
Ключевое слово DELETE может использоваться для постоянного удаления узлов или связей из графа:
graphDb.execute("MATCH (company:Company)" +
" WHERE company.name='example'" +
" DELETE company");
Здесь мы удалили компанию с названием example.
3.6. Привязка параметров
В приведенных выше примерах значения параметров жестко запрограммированы, что не рекомендуется. К счастью,Neo4j предоставляет возможность привязки переменных к запросу:
Map params = new HashMap<>();
params.put("name", "example");
params.put("make", "tesla");
params.put("model", "modelS");
Result result = graphDb.execute("CREATE (example:Company {name:$name}) " +
"-[:owns]-> (tesla:Car {make: $make, model: $model})" +
"RETURN example, tesla", params);
4. Драйвер Java
До сих пор мы рассматривали возможность взаимодействия со встроенным экземпляромNeo4j, однако, по всей вероятности, для производства мы хотели бы запустить автономный сервер и подключиться к нему через предоставленный драйвер. Во-первых, нам нужно добавить еще одну зависимость в наш mavenpom.xml:
org.neo4j.driver
neo4j-java-driver
1.6.2
Вы можете следить заthis link, чтобы проверить наличие последней версии этого драйвера.
Теперь мы можем установить соединение:
Driver driver = GraphDatabase.driver(
"bolt://localhost:7687", AuthTokens.basic("neo4j", "12345"));
Затем создайте сеанс:
Session session = driver.session();
Наконец, мы можем выполнить несколько запросов:
session.run("CREATE (example:Company {name:\"example\"}) " +
"-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" +
"RETURN example, tesla");
Как только мы закончим со всей нашей работой, нам нужно закрыть и сессию, и драйвер:
session.close();
driver.close();
5. Драйвер JDBC
Также можно взаимодействовать сNeo4j через драйвер JDBC. Еще одна зависимость для нашегоpom.xml:
org.neo4j
neo4j-jdbc-driver
3.4.0
Вы можете следоватьthis link, чтобы загрузить последнюю версию этого драйвера.
Затем давайте установим соединение JDBC:
Connection con = DriverManager.getConnection(
"jdbc:neo4j:bolt://localhost/?user=neo4j,password=12345,scheme=basic");
Здесьcon - это обычное соединение JDBC, которое можно использовать для создания и выполнения операторов или подготовленных операторов:
try (Statement stmt = con.
stmt.execute("CREATE (example:Company {name:\"example\"}) "
+ "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})"
+ "RETURN example, tesla")
ResultSet rs = stmt.executeQuery(
"MATCH (company:Company)-[:owns]-> (car:Car)" +
"WHERE car.make='tesla' and car.model='modelX'" +
"RETURN company.name");
while (rs.next()) {
rs.getString("company.name");
}
}
6. Отображение объектов-графиков
Object-Graph-Mapping или OGM - это метод, который позволяет нам использовать POJO нашего домена в качестве сущностей в базе данныхNeo4j. Давайте рассмотрим, как это работает. Первым шагом, как обычно, добавляем новые зависимости в нашpom.xml:
org.neo4j
neo4j-ogm-core
3.1.2
org.neo4j
neo4j-ogm-embedded-driver
3.1.2
Вы можете проверитьOGM Core Link иOGM Embedded Driver Link, чтобы проверить наличие последних версий этих библиотек.
Во-вторых, мы аннотируем наши POJO аннотациями OGM:
@NodeEntity
public class Company {
private Long id;
private String name;
@Relationship(type="owns")
private Car car;
}
@NodeEntity
public class Car {
private Long id;
private String make;
@Relationship(direction = "INCOMING")
private Company company;
}
@NodeEntity сообщаетNeo4j, что этот объект должен быть представлен узлом в результирующем графе. @Relationship сообщает о необходимости создания отношения с узлом, представляющим связанный тип. В этом случаеcompany владеетcar.
Обратите внимание, чтоNeo4j требует, чтобы каждая сущность имела первичный ключ, при этом по умолчанию выбирается поле с именемid. Можно использовать поле с альтернативным именем, пометив его@Id @GeneratedValue.
Затем нам нужно создать конфигурацию, которая будет использоваться для начальной загрузки OGMNeo4j. Для простоты, давайте использовать встроенную базу данных только в памяти:
Configuration conf = new Configuration.Builder().build();
После этого мы инициализируемSessionFactory с помощью созданной конфигурации и имени пакета, в котором находятся наши аннотированные POJO:
SessionFactory factory = new SessionFactory(conf, "com.example.graph");
Наконец, мы можем создатьSession и начать его использовать:
Session session = factory.openSession();
Car tesla = new Car("tesla", "modelS");
Company example = new Company("example");
example.setCar(tesla);
session.save(example);
Здесь мы инициировали сеанс, создали наши POJO и попросили сеанс OGM сохранить их. Neo4j Среда выполнения OGM прозрачно преобразовала объекты в набор запросовCypher, которые создали соответствующие узлы и ребра в базе данных.
Если этот процесс кажется знакомым, это потому, что это так! Именно так работает JPA, единственное отличие состоит в том, переводится ли объект в строки, которые сохраняются в СУБД, или в виде последовательности узлов и ребер, сохраняемых в базе данных графа.
7. Заключение
В этой статье были рассмотрены некоторые основы граф-ориентированной базы данных Neo4j.
Как всегда, весь код в этой записи доступенover on Github.