2016-09-18 72 views
0

鑑於模型結合Neo4j密碼查詢的最佳方法(UNION的替代方法)?

有一個模型與他們之間的類別和關係。 對於關係,可以指定它是否綁定到特定的開始或結束類別。

的四種關係:

  • 只有開始類別規定(例如:「呼出」)
  • 只有類目指定(例如:「進入」)
  • 兩者,開始和結束的類別被指定(例如:「傳出和傳入」)
  • 既不啓動也不端類別被指定(例如:「未結合」)

編號:

MERGE (cat:ModelCategory {title:'Cat'}) 
MERGE (rel1:ModelRelation {title:'Outgoing'}) 
MERGE (rel2:ModelRelation {title:'Incoming'}) 
MERGE (rel3:ModelRelation {title:'Outgoing and Incoming'}) 
MERGE (rel4:ModelRelation {title:'Unbound'}) 
MERGE (rel1)-[:STARTS_AT]->(cat) 
MERGE (rel2)-[:ENDS_AT]->(cat) 
MERGE (rel3)-[:STARTS_AT]->(cat) 
MERGE (rel3)-[:ENDS_AT]->(cat) 

Neo4j Browser Screenshot

單查詢

如果選擇「貓」作爲開始節點,要知道,這關係並導致終端節點可以被創建,你可以使用單查詢:

// Relations with current source and a target 
// Returns relation "Outgoing and Incoming" 
MATCH (relation:ModelRelation)-[STARTS_AT]->(:ModelCategory{title:"Cat"}), 
(relation)-[ENDS_AT]->(target) 
RETURN DISTINCT relation, target 

// Relations with current source and without target 
// Returns relation "Outgoing" 
MATCH (relation:ModelRelation)-[STARTS_AT]->(:ModelCategory{title:"Cat"}) 
WHERE NOT (relation)-[:ENDS_AT]->() 
MATCH (allCategories:ModelCategory) 
RETURN relation, allCategories as target 

// Relations with target, without source 
// Returns relation "Incoming" 
MATCH (relation:ModelRelation)-[ENDS_AT]->(target) 
WHERE NOT (relation)-[:STARTS_AT]->() 
RETURN relation, target 

// Relations without source or target 
// Returns relation "Unbound" 
MATCH (relation:ModelRelation) 
WHERE NOT (relation)-[:STARTS_AT]->() AND NOT (relation)-[:ENDS_AT]->() 
MATCH (allCategories:ModelCategory) 
RETURN relation, allCategories as target 

問題

組合這四個查詢的最佳方式是什麼?
最簡單的解決方案是在語句之​​間添加UNION。
也許最好首先獲取標籤ModelRelation和ModelCategory的所有節點並在子圖上執行進一步的查詢?

更新

更好的解決辦法是有或沒有指定的目標之間的關係,以disginguish。 (導致一個類別或所有類別。)一個UNION仍然是必需的,並且這兩個子查詢的第一部分是相同的。

// Relations which start at selected category or have no specified start 
MATCH (relation:ModelRelation) 
WHERE (relation)-[:STARTS_AT]->(:ModelCategory{title:"Cat"}) OR 
     NOT (relation)-[:STARTS_AT]->() 

// Relations with specified targets 
Match (relation)-[ENDS_AT]->(target) 
RETURN relation, target 

UNION 

// Relations which start at selected category or have no specified start 
MATCH (relation:ModelRelation) 
WHERE (relation)-[:STARTS_AT]->(:ModelCategory{title:"Cat"}) OR 
     NOT (relation)-[:STARTS_AT]->() 

// Relations without specified targets 
MATCH (relation) 
WHERE NOT (relation)-[:ENDS_AT]->() 
MATCH (allCategories:ModelCategory) 
RETURN relation, allCategories as target 

回答

1

使用濾波器符號和可變長度的路徑捕獲所有的這在一個查詢中,然後使用CASE語句與allCategories取代空值。

MATCH (m:ModelCategory) 
WITH COLLECT(m) AS allCategories 
MATCH path = (:ModelCategory) <- [:STARTS_AT*0..1] - (:ModelRelation) - [:ENDS_AT*0..1] -> (:ModelCategory) 
WITH CASE WHEN ANY(x in RELATIONSHIPS(path) WHERE TYPE(x) = 'STARTS_AT') THEN NODES(path)[0] ELSE allCategories END AS start, 
[x IN NODES(path) WHERE x:ModelRelation][0] as relation, 
CASE WHEN ANY(x IN RELATIONSHIPS(path) WHERE TYPE(x) = 'ENDS_AT') THEN LAST(NODES(path)) ELSE allCategories END AS end 
RETURN start, relation, end 

一般來說,你可以總是與COLLECTCASE,並且或者OPTIONAL MATCH或長度爲0的路徑的正確的組合替換UNION查詢。這是值得的,因爲你可以在結果上運行聚合,而不是在每個查詢中返回相同的列布局。

編輯:一個更簡單的版本,每個關係返回一行。

MATCH (m:ModelCategory) 
WITH COLLECT(m) AS allCategories 
MATCH (relation:ModelRelation) 
OPTIONAL MATCH (relation) - [:STARTS_AT] -> (start:ModelCategory) 
OPTIONAL MATCH (relation) - [:ENDS_AT] -> (end:ModelCategory) 
WITH COLLECT(start) AS starts, relation, COLLECT(end) AS ends, allCategories 
RETURN 
CASE starts WHEN [] THEN allCategories ELSE starts END AS relationStarts, 
relation, 
CASE ends WHEN [] THEN allCategories ELSE ends END AS relationEnds