距離上一篇neo4j的博客有好長一段時間了哈,真是懶啊嗷嗷嗷……
咳咳,言歸正傳,學習如何用java創建一個neo4j數據庫,首先!讓我們一起來定個小目標(> ~ <):構建一個長這樣的圖:
有一箇中心結點,它有一些屬性,其外有一級二級結點。
一、創建數據庫
使用 GraphDatabaseService 實例化數據庫,
graphDB = new GraphDatabaseFactory().newEmbeddedDatabase(filePath)
結點的創建用: graphDB.createNode()
結點間的關係: createRelationshipTo(theOtherNode, relationshipType)
public void init(Boolean deletOrNot, String path) throws IOException{
//創建數據庫,並初始化結點,初始化中心結點與一級結點間的關係
if(deletOrNot){//如果數據庫文件已經存在,則刪除以前的
FileUtils.deleteRecursively(new File(path));
}
this.graphDB =new GraphDatabaseFactory().newEmbeddedDatabase(new File(path));
registerShutdownHook(this.graphDB);
try(Transaction tx = this.graphDB.beginTx()){
this.movie = this.graphDB.createNode();
this.manufacture = this.graphDB.createNode();
this.theme = this.graphDB.createNode();
this.contence = this.graphDB.createNode();
this.roleList = this.graphDB.createNode();
//建立關係
this.movie.createRelationshipTo(this.manufacture, MyRelationshipTypes.MADED_BY);
this.movie.createRelationshipTo(this.theme, MyRelationshipTypes.THEME_IS);
this.movie.createRelationshipTo(this.contence, MyRelationshipTypes.CONTENCE_IS);
this.movie.createRelationshipTo(this.roleList, MyRelationshipTypes.PLAYED_BY);
//檢索一下中心結點及一級結點的關係,用來檢測
// Iterable<Relationship> allRelationships = this.movie.getRelationships();
// for(Relationship r: allRelationships){
// System.out.println("relationName: " + r.getType().name());
// }
tx.success();
}
}
二、自定義結點標籤和關係
爲結點貼上標籤可以方便我們的查找和集合操作。而在neo4j中標籤和結點間的關係都可以人爲定義
//labels
public enum Labels implements Label{
MOVIE, MANUFACTURE, THEME, ROLELIST, CONTENCE,
COMPANY, DIRECTOR, SCRIPTWRITER, ROLE, ACTOR
}
//relationships
public enum MyRelationshipTypes implements RelationshipType{
MADED_BY, THEME_IS, CONTENCE_IS, PLAYED_BY,
COMPANY_IS, DIRECTED_BY, WOROTE_BY, ROLE_IS, ACTOR_BY
}
private void registerShutdownHook(final GraphDatabaseService graphDB){
//關閉寄存器
Runtime.getRuntime().addShutdownHook(new Thread(){
public void run(){
graphDB.shutdown();
}
});
}
三、填補每一個結點
添加屬性及標籤進行補充。
屬性類型支持多種基本數據類型及數組。屬性的設置用:
node.setProperty("propertyName",name)
,
檢索時用 getProperty("propertyName")
即可。
我們的中心結點有屬性:名字,評分,票房,上映時間,地區,片長,圖片,關鍵詞。貼有標籤:電影。
neo4j的每一個操作稱爲:事務。每一項事務都必須用下面的結構進行包裝
try(Transaction tx = graphDB.beginTx(){
....
tx.succsee();
}
public void createMovieNode(String name, String score, String boxOffice, String release_time, String area, String length, String imgurl, String[] keywords){
try(Transaction tx = graphDB.beginTx()){
this.movie.setProperty("name", name);
this.movie.setProperty("score", score);
this.movie.setProperty("boxOffice", boxOffice);
this.movie.setProperty("release_time", release_time);
this.movie.setProperty("area", area);
this.movie.setProperty("length", length);
this.movie.setProperty("imgurl", imgurl);
this.movie.setProperty("keywords", keywords);
this.movie.addLabel(Labels.MOVIE);
System.out.println("success to create movie node");
tx.success();
}
}
四、通過標籤查找結點
用findNode找到對應結點,然後我們可以用 ResourceIterator 接載所有有該標籤的結點。
public ArrayList<Node> findNodeByLabel(Labels label){
ArrayList<Node> nodeList = new ArrayList<Node>();
Node node = null;
try(Transaction tx = this.graphDB.beginTx()){
ResourceIterator<Node> iterator = this.graphDB.findNodes(label);
while(iterator.hasNext()){
node = iterator.next();
nodeList.add(node);
}
if(node == null){
System.out.println("wrong to find the node" + label.name());
}
tx.success();
}
return nodeList;
}
五、通過關係查找結點
注意noe4j中關係的指向是有方向性的,所以一條關係會有startNode、endNode之分,而我們這個圖其實並不講究出入方向,因此並沒有設置。
node.getRelationships()可以獲得該結點所有的關係,不論出入方向
relationship.getEndNode()獲得被指向的結點
relatonship.getOtherNode(node)關係中的node外另一個結點
public Node returnRelativeActor(Node role){
Node actor = null;
try(Transaction tx = this.graphDB.beginTx()){
Iterable<Relationship> allRelationships = role.getRelationships();
for(Relationship r: allRelationships){
System.out.println(r.toString());
if(r.getType().name().equalsIgnoreCase("ACTOR_BY")){
System.out.println("success to find the relative actor");
actor = r.getEndNode();
}
}
}
return actor;
}
上面這兩種查找方法都沒有用到neo4j引以爲豪的遍歷,但也可借這兩個例子看出設置標籤的方便之處(事實上是因爲我當時做的時候還沒摸透遍歷這一塊所以用了很簡單的方法,哦哈哈哈哈~)
neo4j的遍歷使用的是org.neo4j.graphdb.traversal.TraversalDescription接口,我們用它定義遍歷的規則,比如說我們要查找主題這個結點,除了像上面第四點寫的通過標籤方法,我們也可以通過關係遍歷
TraversalDescription traversal = this.graphDB.traversalDescription() //定義規則
.breadthFirst() //寬度遍歷
.relationships(MyRelationshipTypes.THEME)//這裏可以是標籤列表也可以是關係列表
.evaluator(Evaluators.atDepth(2))//只查找深度爲2的結點
.uniqueness(Uniqueness.NODE_GLOBAL)//唯一性,一下兩個是最常用的參數,除此之外還有其他四個
//NODE_GLOBAL 被遍歷過的結點不會再被訪問
//NODE_PATH 一條路徑只被遍歷一次,一個結點可以被訪問多次,只要不是同一條路徑上
traversal中只是定義了遍歷的規則,而我們的遍歷結果是一個Traverser,是Path的集合
Traverser tra = traversal.traverse(movie)//movie是中心結點,也是遍歷的起始結點
for(Path path: tra){
System.out.println(path.startNode().getProperty("name") + "--" + path.length() + "--" + path.endNode().getProperty("name");
這樣我們會得到結果
但丁密碼--1--Node[1]
在我的項目中,關於圖譜現在有這麼幾個類:
MovieGraph.java 基層數據庫的構建
CreateGraph.java 匹配獲取字段並動態構建一部電影的圖
ReadGraph.java 封裝數據庫的信息,以便前端使用
SearchGraph.java 是爲了自動問答時搜尋答案
具體實現可以參考我的github