本文的第一部分介紹了Neo4j及其Cypher查詢語言。若是您已經閱讀了第1部分,那麼您已經瞭解了爲何Neo4j和其餘圖形數據庫特別受html
而後,咱們使用Cypher查詢語言對Neo4j中的一個家庭進行建模,包括年齡,性別和家庭成員之間的關係等我的屬性。咱們建立了一些朋友來擴大咱們的社交圖,而後添加鍵/值對來生成每一個用戶看過的電影列表。最後,咱們查詢了咱們的數據,使用圖形分析來搜索一個用戶沒有看到但可能喜歡的電影。java
Cypher查詢語言與SQL等傳統數據查詢語言不一樣。Cypher並無考慮像表和外鍵關係這樣的事情,而是強迫您考慮節點,節點之間的天然關係以及各個節點之間能夠在各個關係之間進行的各類遍歷。使用Cypher,您能夠建立本身的心理模型,瞭解真實世界的實體如何相互關聯。須要一些練習來擅長編寫Cypher查詢,可是一旦你理解了它們的工做方式,即便很是複雜的查詢也是有意義的。node
在使用Cypher查詢語言對Neo4j中的社交圖建模並使用該社交圖編寫查詢後,編寫Java代碼以對該圖執行查詢很是簡單。在本文中,您將學習如何將Neo4j與Java Web客戶端應用程序集成,您可使用它來查詢咱們在第1部分中建立的社交圖。數據庫
咱們的第一步是建立一個新的Maven項目:apache
mvn archetype:generate -DgroupId=com.geekcap.javaworld -DartifactId=neo4j-example -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false複製代碼
打開您的pom.xml
文件並添加Neo4j驅動程序,在撰寫本文時版本爲1.4.1:bash
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>1.4.1</version>
</dependency> 複製代碼
接下來,建立一個Neo4j Driver
,以下所示:網絡
Driver driver = GraphDatabase.driver( "bolt://localhost:7687", AuthTokens.basic("neo4j", "neo4j"));複製代碼
本GraphDatabase
類有一個叫作靜態方法driver()
接受一個鏈接Neo4j的URL和AuthToken
。您可使用默認用戶名和密碼「neo4j」 建立基本AuthToken
。session
在Driver
與Neo4j的促進通訊。咱們經過要求Driver
建立Session
對象來執行查詢,以下所示:app
Session session = driver.session();複製代碼
該org.neo4j.driver.v1.Session
接口對Neo4j執行事務。在最簡單的形式中,咱們能夠執行繼承自的run()
方法。而後,將開始一個事務,運行咱們的語句,並提交該事務。Sessionorg.neo4j.driver.v1.StatementRunnerSession
maven
該StatementRunner
接口定義了的幾個變型run()
方法。這是咱們將使用的那個:
StatementResult run(String statementTemplate, Map<String,Object> statementParameters)複製代碼
該statementTemplate
是一個包含咱們的Cypher查詢的String
,statementParameters
包括咱們將使用的命名參數。例如,咱們可能想要建立具備指定名稱和年齡的Person
:
session.run("CREATE (person: Person {name: {name}, age: {age}})",
parameters("name", person.getName(), "age", person.getAge()));複製代碼
{name}和{age}
命名,能夠經過傳遞解析爲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
對象在其返回類型中提供靈活性的緣由。
如今咱們將學習到目前爲止所學到的知識,並將Java中的示例應用程序組合在一塊兒。基於第1部分中的建模和查詢示例,此應用程序建立Person
對象,查找全部Person
對象,查找a的全部朋友Person
,並查找Person
已看過的全部電影。
清單1和清單2建立了定義 Person
和a的Java類Movie
。清單3顯示了咱們的測試類的源代碼:Neo4jClient
。
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;
}
}複製代碼
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;
}
}複製代碼
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());
}
}
}複製代碼
在Neo4jClient
類在其構造中建立的Neo4j Driver
。而後它的方法使用Driver
來建立一個Session
對象以執行Cypher查詢。createPerson()
方法使用「name」和「age」的命名參數執行Cypher查詢CREATE (person:Person {...})
。parameters()
方法將這些參數綁定到指定Person
的名稱和年齡屬性。
findAllPeople()
方法查找Person
數據庫中的全部對象。請注意,此方法會返回全部人,所以若是您有不少人,則可能須要向響應中添加LIMIT
。這是一個例子:
MATCH (person:Person) RETURN person LIMIT 25複製代碼
在這種狀況下,咱們返回完整Person
節點,所以我從Record
中獲取「person」並使用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歲的名爲「Duke」(提示:就像Java同樣)的Person
。它找到了邁克爾的朋友和他所見過的電影。
清單4顯示了Maven pom.xml
文件,咱們用它來構建和運行咱們的應用程序。
<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
依賴項,而後定義三個插件:
com.geekcap.javaworld.neo4j.Neo4jClient
幷包含lib
JAR文件目錄中的全部文件CLASSPATH
。lib
文件夾中。您如今可使用如下命令構建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 Web界面並執行一些查詢!您應該看到Duke已建立並可以驗證結果。
Neo4j是一個管理高度相關數據的圖形數據庫。咱們經過回顧圖形數據庫的需求開始了這種探索,尤爲是在查詢關係中三個以上的分離度時。在開發環境中使用Neo4j進行設置後,咱們花了大部分時間來了解Neo4j的Cypher查詢語言。咱們創建了一個家庭關係網絡,並使用Cypher查詢了這些關係。咱們在該文章中的重點是學習如何以
在第2部分中,您學習瞭如何編寫鏈接到Neo4j並執行Cypher查詢的Java應用程序。咱們採用最簡單(手動)的方法將Java與Neo4j集成。一旦掌握了基礎知識,您可能想要探索將Java與Neo4j集成的更高級方法 - 例如使用Neo4j的對象圖形映射(OGM)庫,Neo4j-OGM和Spring Data。
更多文章歡迎訪問: http://www.apexyun.com
公衆號:銀河系1號
聯繫郵箱:public@space-explore.com
(未經贊成,請勿轉載)