2016-09-18 87 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