可以做到,但我找不到简单的解决方案。所以让我们来看看复杂的吧。
首先,创建一个示例图:
CREATE
(a:Entity {name: 'a'}),
(b:Entity {name: 'b'}),
(c:Entity {name: 'c'}),
(d:Entity {name: 'd'}),
(e:Entity {name: 'e'}),
(a)-[:REL {name: 'r1'}]->(b)
<-[:REL {name: 'r2'}]-(c)
-[:REL {name: 'r3'}]->(d)
-[:REL {name: 'r4'}]->(e)
使用这个查询:
MATCH (e1 {name: 'a'})-[rels*1..4]-(e2 {name: 'e'})
WITH e1, e2, rels,
extract(rel IN rels | startNode(rel)) AS startNodes,
extract(rel IN rels | endNode(rel)) AS endNodes,
range(1, size(rels)-1) AS indexes
WITH e1, e2, rels, startNodes, endNodes, indexes, startNodes[0] AS start
UNWIND indexes AS i
WITH e1, e2,
e1 = start as isOutFirst,
(endNodes[i-1] = startNodes[i] OR
startNodes[i-1] = startNodes[i]) AS isOut
WITH e1, e2, isOutFirst, collect(isOut) AS isOuts
RETURN e1, e2, [isOutFirst] + isOuts AS isOuts
结果是:
╒═════════╤═════════╤═════════════════════════╕
│e1 │e2 │isOuts │
╞═════════╪═════════╪═════════════════════════╡
│{name: a}│{name: e}│[true, false, true, true]│
└─────────┴─────────┴─────────────────────────┘
主要思路如下:
- 我们使用
extract 方法获取每个关系的开始和结束节点。
- 我们使用
range 函数和UNWIND 生成索引列表并在列表上“迭代”。
- 如果 i. 关系从前一个 (i-1.) 关系的任何节点开始,则它是传出 (
isOut) 关系。
- 0. 关系没有先前的关系,因此我们将其单独处理 (
isOutFirst)。
- 我们将
isOut 值收集到isOuts 列表中。
- 我们将
isOutFirst 变量和isOuts 列表组合成一个列表。
您可以UNWIND结果并添加对应的关系类型:
MATCH (e1 {name: 'a'})-[rels*1..4]-(e2 {name: 'e'})
WITH e1, e2, rels,
extract(rel IN rels | startNode(rel)) AS startNodes,
extract(rel IN rels | endNode(rel)) AS endNodes,
range(1, size(rels)-1) AS indexes
WITH e1, e2, rels, startNodes, endNodes, indexes, startNodes[0] AS start
UNWIND indexes AS i
WITH e1, e2, rels,
e1 = start as isOutFirst,
(endNodes[i-1] = startNodes[i] OR
startNodes[i-1] = startNodes[i]) AS isOut
WITH e1, e2, rels, isOutFirst, collect(isOut) AS isOuts
WITH e1, e2, rels,
[isOutFirst] + isOuts AS isOuts,
range(0, size(rels)-1) AS indexes2
UNWIND indexes2 AS i
RETURN e1, e2, type(rels[i]) AS relType, isOuts[i] AS isOut
这会导致:
╒═════════╤═════════╤═══════╤═════╕
│e1 │e2 │relType│isOut│
╞═════════╪═════════╪═══════╪═════╡
│{name: a}│{name: e}│REL │true │
├─────────┼─────────┼───────┼─────┤
│{name: a}│{name: e}│REL │false│
├─────────┼─────────┼───────┼─────┤
│{name: a}│{name: e}│REL │true │
├─────────┼─────────┼───────┼─────┤
│{name: a}│{name: e}│REL │true │
└─────────┴─────────┴───────┴─────┘
更新:您可以使用方向从路径中以正确的顺序提取节点:
MATCH (e1 {name: 'a'})-[rels*1..4]-(e2 {name: 'e'})
WITH e1, e2, rels,
extract(rel IN rels | startNode(rel)) AS startNodes,
extract(rel IN rels | endNode(rel)) AS endNodes,
range(1, size(rels)-1) AS indexes
WITH e1, e2, rels, startNodes, endNodes, indexes, startNodes[0] AS start
UNWIND indexes AS i
WITH e1, e2, rels,
e1 = start as isOutFirst,
(endNodes[i-1] = startNodes[i] OR
startNodes[i-1] = startNodes[i]) AS isOut
WITH e1, e2, rels, isOutFirst, collect(isOut) AS isOuts
WITH e1, e2, rels,
[isOutFirst] + isOuts AS isOuts,
range(0, size(rels)-1) AS indexes2
UNWIND indexes2 AS i
RETURN e1, e2, type(rels[i]) AS relType,
CASE isOuts[i]
WHEN true THEN startNode(rels[i])
ELSE endNode(rels[i])
END AS node1,
CASE isOuts[i]
WHEN true THEN endNode(rels[i])
ELSE startNode(rels[i])
END AS node2
这会导致:
╒═════════╤═════════╤═══════╤═════════╤═════════╕
│e1 │e2 │relType│node1 │node2 │
╞═════════╪═════════╪═══════╪═════════╪═════════╡
│{name: a}│{name: e}│REL │{name: a}│{name: b}│
├─────────┼─────────┼───────┼─────────┼─────────┤
│{name: a}│{name: e}│REL │{name: b}│{name: c}│
├─────────┼─────────┼───────┼─────────┼─────────┤
│{name: a}│{name: e}│REL │{name: c}│{name: d}│
├─────────┼─────────┼───────┼─────────┼─────────┤
│{name: a}│{name: e}│REL │{name: d}│{name: e}│
└─────────┴─────────┴───────┴─────────┴─────────┘
限制:如果图中有一个 2 长度的圆,上述解决方案可能不起作用,例如对于图形 (a)<-[r1]-(b)<-[r2]-(a),它们错误地将 (b)<-[r2]-(a) 标记为其中一条路径的传出。