Neo4j 是一套原生實現 (底層設計就是為了圖資料庫設計,而不是用例如一般關聯式資料庫去模擬) 圖資料庫(Graph Database) 的工具
Neo4j Community Edition 版本可以到
Neo4j 官網的下載中心 免費下載使用,
除了有啟動 Neo4j server 的功能外還提供了以網頁存取的方便介面 。
下載 Neo4j Community Edition 後,把下載下來的 zip 檔解壓縮,
進入到資料夾裡的 bin 資料夾,用命令列模式 (command line)
打上
neo4j console
指令後,可以用瀏覽器到 http://localhost:7474/browser/ 看到 UI 介面,提供各種功能,例如執行語法及可視化結果,預設登入 Database 的帳號密碼會都是 "neo4j" ,可以自行修改。
這邊紀錄下使用 Java 去讀取 Neo4j 查詢結果的方法,首先來看下需要的依賴 Maven Dependency:
<!-- https://mvnrepository.com/artifact/org.neo4j.driver/neo4j-java-driver --> <dependency> <groupId>org.neo4j.driver</groupId> <artifactId>neo4j-java-driver</artifactId> <version>4.4.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.neo4j/neo4j-jdbc-driver --> <dependency> <groupId>org.neo4j</groupId> <artifactId>neo4j-jdbc-driver</artifactId> <version>4.0.4</version> <scope>runtime</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.neo4j/neo4j --> <!-- neo4j embedded version --> <dependency> <groupId>org.neo4j</groupId> <artifactId>neo4j</artifactId> <version>4.4.2</version> </dependency>以上三個 neo4j 的 dependency 可以擇一使用,
可依你想要存取 neo4j 的方式來選擇,分述如下:
- org.neo4j.driver 的 neo4j-java-driver :
使用 Driver 的方式來存取 neo4j ,有較接近 neo4j 原生結構的類別可操作使用,
需要跟已開啟的 neo4j server 做連線,使用像例如
neo4j://localhost:7687
這樣的方式來操縱 neo4j 資料庫。 - org.neo4j 的 neo4j-jdbc-driver :
使用 JDBC 的方式來存 neo4j ,
需要跟已開啟的 neo4j server 做連線,使用像例如
jdbc:neo4j:bolt://localhost:7687?user=xxx,password=xxx,scheme=basic
的方式操縱 neo4j 資料庫。
跟 neo4j-java-driver 比起來,neo4j-jdbc-driver 沒有接近 neo4j 原生結構的類別可操作使用,
只能使用 jdbc 的 (Map) ResultSet.getObject() 方式等存取 - org.neo4j 的 neo4j :
使用 嵌入式(embedded) 的方式來存取本地端的 neo4j 資料庫檔案,
可以直接處理本地端 neo4j 資料庫檔案 (通常為一個資料夾),
不需開啟 neo4j server 做連線,適合用在無 server 的環境,
有較接近 neo4j 原生結構的類別可操作使用,
例如可直接對整個 neo4j-community-4.4.2 資料夾及指定 Database 名稱來做存取。
內容為一個英雄人物曾當過哪些英雄的關係圖,像是這個樣子:
Bruce Wayne -[hasBeenHero] -> Batman
Dick Grayson -[hasBeenHero] -> Batman
Dick Grayson -[hasBeenHero] -> Nightwing
Dick Grayson -[hasBeenHero] -> Robin
建構資料的語法如下
//create "Persion" nodes MERGE (bruceWayne:Person {name: 'Bruce Wayne'}) MERGE (dickGrayson:Person {name: 'Dick Grayson'}) //create "Hero" nodes WITH bruceWayne, dickGrayson, [ {name: 'Batman'}, {name: 'Nightwing'}, {name: 'Robin'} ] AS heros //create and set relatoinship FOREACH (hero in heros | CREATE (h:Hero) SET h = hero CREATE (dickGrayson)-[:hasBeenHero]->(h) ) WITH bruceWayne MATCH (batman:Hero{name:'Batman'}) CREATE (bruceWayne)-[:hasBeenHero]->(batman)用視覺化來看的話資料庫結果會如下圖:
接下來我們來看看要如何用 Java 把資料庫的 Node 和 Relationship 都查出來,
以下直接上 Java 程式碼,實現了三個 method ,分別對應了上述的三種存取 neo4j Database 的方式,分別是:
queryByDriver() 對應 org.neo4j.driver 的 neo4j-java-driver
queryByJdbc() 對應 org.neo4j 的 neo4j-jdbc-driver
queryByEmbeddedMode() 對應 org.neo4j 的 neo4j
Neo4jTest.java :
package main; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.neo4j.dbms.api.DatabaseManagementService; import org.neo4j.dbms.api.DatabaseManagementServiceBuilder; import org.neo4j.driver.AuthTokens; import org.neo4j.driver.Driver; import org.neo4j.driver.GraphDatabase; import org.neo4j.driver.Record; import org.neo4j.driver.Result; import org.neo4j.driver.Session; import org.neo4j.driver.types.Node; import org.neo4j.driver.types.Relationship; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Transaction; import org.neo4j.kernel.impl.core.NodeEntity; import org.neo4j.kernel.impl.core.RelationshipEntity; public class Neo4jTest { public static void main(String... args) throws Exception { String databaseName = "neo4j"; String userName = "neo4j"; String password = "neo4j"; String neo4jServerUrl = "localhost:7687"; Path neo4jDBHomeDirectoryPath = Paths.get(ClassLoader.getSystemResource("neo4j-community-4.4.2").toURI()); //or if the database directory is located on other path: //Path neo4jDBHomeDirectoryPath = Paths.get("D:\\xxx\\yyy\\neo4j-community-4.4.2"); queryByDriver("neo4j://" + neo4jServerUrl, userName, password); queryByJdbc(neo4jServerUrl, userName, password); queryByEmbeddedMode(neo4jDBHomeDirectoryPath, databaseName); System.out.println("Done"); } public static void queryByDriver(String uri, String username, String password) { try (Driver driver = GraphDatabase.driver(uri, AuthTokens.basic(username, password)); Session session = driver.session();) { List<String> dataList = session.readTransaction(tx -> { List<String> resultList = new ArrayList<String>(); Result result = tx.run("MATCH (person:Person)-[relationship:hasBeenHero]->(hero:Hero) " + "RETURN * " + "ORDER BY person.name, hero.name"); while(result.hasNext()) { Record record = result.next(); Node person = record.get("person").asNode(); Relationship relationship = record.get("relationship").asRelationship(); Node hero = record.get("hero").asNode(); String resultStr = person.get("name").asString() + " -" + relationship.type() + "-> " + hero.get("name").asString(); // System.out.println(resultStr); // who -hasBeenHero-> whatHero resultList.add(resultStr); } return resultList; }); for (String data : dataList) { System.out.println(data); /* output: Bruce Wayne -hasBeenHero-> Batman Dick Grayson -hasBeenHero-> Batman Dick Grayson -hasBeenHero-> Nightwing Dick Grayson -hasBeenHero-> Robin */ } }catch(Exception e) { e.printStackTrace(); } } public static void queryByJdbc(String uri, String username, String password) { try (Connection con = DriverManager.getConnection("jdbc:neo4j:bolt://" + uri + "?user=" + username + ",password=" + password +",scheme=basic"); PreparedStatement pstmt = con.prepareStatement("MATCH (person:Person)-[relationship:hasBeenHero]->(hero:Hero) " + "RETURN * " + "ORDER BY person.name, hero.name"); ResultSet rs = pstmt.executeQuery(); ){ while(rs.next()) { Map person = (Map) rs.getObject("person"); Map relationship = (Map) rs.getObject("relationship"); Map hero = (Map) rs.getObject("hero"); String resultStr = person.get("name") + " -" + relationship.get("_type") + "-> " + hero.get("name"); System.out.println(resultStr); /* output: Bruce Wayne -hasBeenHero-> Batman Dick Grayson -hasBeenHero-> Batman Dick Grayson -hasBeenHero-> Nightwing Dick Grayson -hasBeenHero-> Robin */ } }catch(Exception e) { e.printStackTrace(); } } // Don't need to start server manually, it will start server by itself. // Don't need username and password. public static void queryByEmbeddedMode(Path neo4jDBHomeDirectoryPath, String databaseName) { DatabaseManagementService databaseManagementService = new DatabaseManagementServiceBuilder(neo4jDBHomeDirectoryPath).build(); GraphDatabaseService graphDatabaseService = databaseManagementService.database(databaseName); // Registers a shutdown hook for the Neo4j instance so that it // shuts down nicely when the VM exits (even if you "Ctrl-C" the // running application). // Runtime.getRuntime().addShutdownHook( new Thread() // { // @Override // public void run() // { // databaseManagementService.shutdown(); // } // } ); try(Transaction tx = graphDatabaseService.beginTx();){ org.neo4j.graphdb.Result result = tx.execute("MATCH (person:Person)-[relationship:hasBeenHero]->(hero:Hero) " + "RETURN * " + "ORDER BY person.name, hero.name"); while(result.hasNext()) { Map<String,Object> record = result.next(); NodeEntity person = (NodeEntity) record.get("person"); RelationshipEntity relationship = (RelationshipEntity) record.get("relationship"); NodeEntity hero = (NodeEntity) record.get("hero"); String resultStr = person.getProperty("name") + " -" + relationship.getType().name() + "-> " + hero.getProperty("name"); System.out.println(resultStr); /* output: Bruce Wayne -hasBeenHero-> Batman Dick Grayson -hasBeenHero-> Batman Dick Grayson -hasBeenHero-> Nightwing Dick Grayson -hasBeenHero-> Robin */ } }catch(Exception e) { e.printStackTrace(); } databaseManagementService.shutdown(); } }可以注意到的是,只有 queryByDriver() 和 queryByJdbc() 需要提供帳號及密碼,並且需要連接一個已經啟動的 neo4j Database server。
而 queryByEmbeddedMode() 不需帳號、密碼,也不需要一個已經啟動的 neo4j Database server,
它會直接對本地端的 neo4j Database folder 做存取,因為它會自己啟動 DB server ,
所以不要用例如上述的 neo4j console 指令啟動 server,不然可能會出現
Exception in thread "main" java.lang.RuntimeException: Error starting Neo4j database server at D:\xxx\yyy\neo4j-community-4.4.2\data\databases
的錯誤訊息。
原碼下載分享: