我的neo4j學習筆記

這篇博文目錄如下:
- About neo4j
- Install neo4j
- learn to create and query data
- Import your data
包括對Neo4j圖形數據庫的簡介和其重要組成部分、內部結構的講解,對其查詢語言cypher的介紹和實例。通過實例轉換、比較傳統關係型數據庫與圖形數據庫。希望有時間下一次可以來總結一下用java實現neo4j的學習過程(* ~ *)

About neo4j

Neo4j是一個高性能的,Nosql圖形數據庫。Nosql =no sql,即與傳統的將數據結構化並存儲在表中的數據庫不一樣。Neo4j將數據存儲在網絡上,我們也可以把Neo4j視爲一個圖引擎。我們打交道的是一個面對對象的、靈活的網絡結構而不是嚴格的、靜態的表。傳統關係型數據庫,當數據量很大時,查詢性能會明顯受影響,尤其是一度以上的查詢。但是圖形數據庫卻在這方面表現得很好。
neo4j 支持多種主流編程語言,包括.Net、Java、JavaScript、Python

Install Neo4j

從官網這裏下載neo4j,解壓,然後進入bin文件夾,開啓數據庫

~$ path/to/your/neo4j/file
~$ cd bin
~$./neo4j console

開啓後我們在瀏覽器上訪問 localhost:7474,就可以本地運行

Learn to create and query data

既然Neo4j是數據庫,則必然有它自己的查詢語言。Cypher是一種面向圖形的申明式語言。它由分句、關鍵詞和一些表示判斷、代表函數的語句組成。比如:WHERE,ORDER BY,SKIP LIMIT ,p.unitPrice > 10。與SQL不同的是,cypher是對於圖形模式的表達。我們總是先用MATCH去匹配我們要操作的數據。

  • cypher: cypher是一種申明式查詢語言。可以分解爲下面幾個部分:
    • nodes
      • 我們通常用圓括號來包含節點標示符(當然也可以不用)。節點標籤也會一併註明。比如(p: Person),如果想添加屬性:(p: Person {name: "yinglish"})。 注意:節點標籤、關係類型和屬性名稱區分大小寫。
    • relationships
      • 我們通常用箭頭 –> 表示關係,沒有尖箭頭的如 – 指不強調方向關係。例子:
      • (a)-[:KNOWS|:LIKE]->(b) a到b是“相識”的關係或者”喜歡“
      • (a)-[rel:KNOWS]->(b) 關係的變量名爲rel,類型是 KNOWS
      • -[{since: 2016}]-> 添加了額外的屬性
      • -[:KNOWS*..4]->
        example: a -[rel: type*minHop..maxHop]-> b

        可變數量關係:從a節點到b節點最少可經過minHop、最大可經過maxHop個節點
    • patterns 模式由一個或多個路徑組成,路徑間用逗號分隔,一條路徑就是一個節點和關係的序列,這個序列指定開始和結束節點,如:(a) –> (b),這條路徑開始於a,通過outgoing關係指向b。如果你不在乎具體是哪個節點,不用指定它,只需要用空括號來表示就可以了,如:a –>()–>b。模式是cypher中的關鍵部分,靈活書寫模式能幫我們正確獲取、實現推測計算等等各種任務。

節點和關係是圖數據庫的基石,每個節點都可以有屬性,每個節點每條關係都可以有標籤。因此neo4j也被稱爲Property graph,看個圖也許會更好理解:(當然了,屬性和標籤都是可選的,也可以沒有)
這裏寫圖片描述

cypher是學習neo4j的重中之重,它有很多關鍵詞,很多靈活的搭配與使用,在理解neo4j的最基本要素:節點,關係,模式,標籤,屬性的概念及其相互間的組成關係後,對查詢語句cypher的學習就是下一站要攻克的堡壘。但是在這篇博文不詳細接受,可以通過這份官方的教程細細學習。

下面我們來看一個簡單但足以說明情況的應用實例:
Create a recode for youself
CREATE (you: Person {name: "You"})
RETURN you

And add a properties to this note
MATCH (you: Person {name: "you"})
CREATE (you) -[like:LIKE]->(neo:Database {name: "Neo4j"})
RETURN you, like, neo

Create your friends
MATCH (you: Person {name: "you"})
FOREACH (name in ["Johan", Rajesh", "Anna", "Julia", "Andrew"])
CREATE (you) -[:FRIED]->(: Person {name: name}))

Create second degree friends and expertise
MATCH (neo: Database {name: "Neo4j"})
MATCH (anna: Person {name: "Anna"})
CREATE (anna) -[:FRIEND]->(:Person:Expert {name:" Amanda"}) -[:WORKED_WITH]->(neo)

現在我們創造了一個關係圖如下:
這裏寫圖片描述
Find someone in your network who can help you learn neo4j
MATCH (you {name: "You"})
MATCH (expert) -[:WORKED_WITH]->(db: Database {name:"Neo4j"})
MATCH path = shortestPath ((you)-[: FRIEND*..5]-(expert))
RETURN db.expert, path

更加細緻詳細的學習資料:
neo4j Cypher Refcard (巨詳細的官方手冊)
官網教程
他人博客
他人博客

Import your data

本小節講解如何從傳統數據庫的數據集PostgreSQL(RDBMS)導出數據到Neo4j(GraphDB),使之成圖。從中可以看到一些這兩種數據庫的差別。
RDBMS數據集
用的數據集是NorthWind dataset(可點擊下載),該數據庫的E-R圖(產品,訂單、僱員、消費者等等相關的表)如下:
neo4j

構建圖模型
將一個E-R模型轉換成圖模型時注意:
1、一行數據表示一個節點
2、一個表名對應一個Label名
NorthWind dataset表示成圖模型的一個局部示意圖如下
(僱員Employee銷售【SOLE】訂單Order,對某種產品的需求產生【PRODUCT】了某個產品Product,該產品是商品目錄Category中的一種【PART OF】,由供應商Supplier提供【SUPPLIES】):
localExam

那麼我們的圖模型和關係模型的差別在哪裏呢?
- 前者沒有空節點。在關係數據庫中,如果一個僱員不需要向誰報告,他在“ReportsTo”這一列的屬性爲空,而在圖模型中,我們只是不需要爲他添加一條指向邊而已。
- 能夠更詳細地描述關係。比如說,我們能夠直觀地瞭解到一個僱員售賣一件產品,而不必通過外鏈在僱員表和產品表中查找。邊上也可以添加元數據。
- 前者對於描述網絡關係更規範。

將數據導出成csv
導出數據主要是 COPY語句,比如這樣:COPY (SELECT * FROM customers) TO '/tmp/customer.csv' WITH CSV header; 把customers表中的數據導出
用Cypher導入數據
我們把數據從PostgreSQL中導出後,用LOAD CSV把CSV文件的內容轉爲圖數據
First, create the nodes

//Create periodic commit
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:customers.csv" AS row
CREATE (:Customer {companyName: row.CompanyName, customerID: row.CustomerID, fax: row.Fax, phone: row.Phone});

//Create products
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:products.csv" AS row
CREATE (:Product {productName: row.ProductName, productID: row.ProductID, unitPrice: toFloat(row.UnitPrice)});

// Create suppliers
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:suppliers.csv" AS row
CREATE (:Supplier {companyName: row.CompanyName, supplierID: row.SupplierID});

// Create employees
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:employees.csv" AS row
CREATE (:Employee {employeeID:row.EmployeeID,  firstName: row.FirstName, lastName: row.LastName, title: row.Title});

// Create categories
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:categories.csv" AS row
CREATE (:Category {categoryID: row.CategoryID, categoryName: row.CategoryName, description: row.Description});

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:orders.csv" AS row
MERGE (order:Order {orderID: row.OrderID}) ON CREATE SET order.shipName =  row.ShipName;

create indexes
接下來在我們剛剛創建的節點上添加索引,以確保下一步添加關係時我們可以快速地找到節點

CREATE INDEX ON :Product(productID);
CREATE INDEX ON :Product(productName);
CREATE INDEX ON :Category(categoryID);
CREATE INDEX ON :Employee(employeeID);
CREATE INDEX ON :Supplier(supplierID);
CREATE INDEX ON :Customer(customerID);
CREATE INDEX ON :Customer(customerName);
CREATE CONSTRAINT ON (o:Order) ASSERT o.orderID IS UNIQUE;

create relationships among orders, products and employees

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:orders.csv" AS row
MATCH (order:Order {orderID: row.OrderID})
MATCH (product:Product {productID: row.ProductID})
MERGE (order)-[pu:PRODUCT]->(product)
ON CREATE SET pu.unitPrice = toFloat(row.UnitPrice), pu.quantity = toFloat(row.Quantity);


USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:orders.csv" AS row
MATCH (order:Order {orderID: row.OrderID})
MATCH (employee:Employee {employeeID: row.EmployeeID})
MERGE (employee)-[:SOLD]->(order);

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:orders.csv" AS row
MATCH (order:Order {orderID: row.OrderID})
MATCH (customer:Customer {customerID: row.CustomerID})
MERGE (customer)-[:PURCHASED]->(order);

create relationships among products, suppliers and categories

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:products.csv" AS row
MATCH (product:Product {productID: row.ProductID})
MATCH (supplier:Supplier {supplierID: row.SupplierID})
MERGE (supplier)-[:SUPPLIES]->(product);

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:products.csv" AS row
MATCH (product:Product {productID: row.ProductID})
MATCH (category:Category {categoryID: row.CategoryID})
MERGE (product)-[:PART_OF]->(category);

create “REPORTS_TO”
用REPORTS_TO來表示員工之間的報告關係

USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:employees.csv" AS row
MATCH (employee:Employee {employeeID: row.EmployeeID})
MATCH (manager:Employee {employeeID: row.ReportsTo})
MERGE (employee)-[:REPORTS_TO]->(manager);

最後圖形如下:

在這個圖上我們來嘗試使用一個查詢語句吧~~
員工之間是怎麼報告的呢?

MATCH path = (e:Employee)<-[:REPORTS_TO]-(sub)
RETURN e.employeeID AS manager, sub.employeeID AS employee;

返回:


manager employee
2 1
2 3
2 4
2 5
2 8
5 6
5 7
5 9

可見僱員6,7,9向僱員5彙報工作,僱員5同僱員1,3,4,8一起向僱員2彙報。當你熟悉cypher語句後你就可以自己這樣玩啦!~你會發現cypher的強大與靈活噠:)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章