1
votes

I'm looking for a way to batch create relationships among similar/parallel paths in neo4j.

A sample graph may look like this:

enter image description here

As you can see, the pink node(the one in the center) :WRAPS 3 yellow nodes, and each yellow node :WRAPS 2 red nodes. I'm trying to create 3 :PARALLEL relationship between each possible pair of 3 nodes. I tried this Cypher statement:

MATCH (pink:Slide)-[:WRAPS]->(yellow:GroupBox)-[:WRAPS*]->(red:Content)
WHERE pink.uuid = "ca7e1d47-1fbe-4008-9617-ef41c8a04316"
MATCH path = (yellow)-[rel]->(red)
RETURN path

It returns all yellow nodes and the associated red nodes. The graph looks like this:

enter image description here

However, since path's class is Path, not List, I can't use unwind/foreach to loop through them. I also tried relationships(path) but it's returning a bunch of empty arrays. I intend to compare the length of and labels of nodes in each path, but can't find a way to do so. Could you help with it?

1

1 Answers

0
votes

Creating your graph

For the ease of possible further answers and solutions I note my graph creating statement:

CREATE
  // left bunch
  (pink:PinkNode {name: '369'})-[:WRAPS]->(yellow1:YellowNode {name: '190'}),
  (yellow1)-[:WRAPS]->(red1:RedNode {name: '201'}),
  (yellow1)-[:WRAPS]->(red2:RedNode {name: '198'}),
  (pink)-[:WRAPS]->(red1),
  (pink)-[:WRAPS]->(red2),

  // upper bunch
  (pink)-[:WRAPS]->(yellow2:YellowNode {name: '195'}),
  (yellow2)-[:WRAPS]->(red3:RedNode {name: '204'}),
  (yellow2)-[:WRAPS]->(red4:RedNode {name: '208'}),
  (pink)-[:WRAPS]->(red3),
  (pink)-[:WRAPS]->(red4),

  // lower bunch
  (pink)-[:WRAPS]->(yellow3:YellowNode {name: '192'}),
  (yellow3)-[:WRAPS]->(red5:RedNode {name: '208'}),
  (yellow3)-[:WRAPS]->(red6:RedNode {name: '210'}),
  (pink)-[:WRAPS]->(red5),
  (pink)-[:WRAPS]->(red6),

  // "free" red ones
  (pink)-[:WRAPS]->(red7:RedNode {name: '255'}),
  (pink)-[:WRAPS]->(red8:RedNode {name: '166'}),
  (pink)-[:WRAPS]->(red9:RedNode {name: '264'}),
  (pink)-[:WRAPS]->(red10:RedNode {name: '269'});

Solution

All possible relationships between your three nodes pairs you will achieve with the following Cypher statement:

CALL apoc.periodic.COMMIT('
MATCH
  (pink:PinkNode)-[:WRAPS]->(yellow:YellowNode)-[:WRAPS]->(red:RedNode)
WITH yellow AS startNode, yellow AS endNode WHERE NOT (startNode)-[:PARALLEL]->(endNode) AND id(startNode) < id(endNode)
CREATE (startNode)-[:PARALLEL]->(endNode)
RETURN count(*)
', {limit: 10000});

Underlying Idea

Based on the identification and selection of your three-nodes-pairs in line 3, I check in line 4 if your desired :PARALLEL relationship already exists. If not, I create it (line 5). By means of the APOC library I rerun this statement until all relationships are created.

Especially for graph processing it is useful to run a query repeatedly in separate transactions until it doesn’t process and generates any results anymore. So you can iterate in batches over elements that don’t fulfill a condition and update them so that they do afterwards.

The query is executed repatedly in separate transactions until it returns 0.

(taken from Neo4j APOC procedure index at GitHub)

The id comparison in line 4 avoids having two relationships per pair (one in each direction) and prevents creating the relationship from nodes to themselves.