1
votes

I have 2 queries in neo4j

MERGE (f:Foo {id:1}) 
MERGE (b:Bar {id:1}) 
with f,b 
FOREACH (i IN range(0,999) | create (f)-[:Qux]->(b));

Added 2 labels, created 2 nodes, set 2 properties, created 1000 relationships, statement executed in 39 ms.

and

MERGE (f:Foo {id:1}) 
MERGE (b:Bar {id:1}) 
with f,b 
CREATE (f) - [:Qux] -> (b)
CREATE (f) - [:Qux] -> (b)
... (1000 times)
CREATE (f) - [:Qux] -> (b)

Added 2 labels, created 2 nodes, set 2 properties, created 1000 relationships, statement executed in 8301 ms.

How come it is so much slower to create relationships with statements than with a loop?

I want to be able to create many relationships at once but a loop isn't appropriate as I want to include data on each individual relationship. How could I do this fast without using a loop. I assume something about my syntax is making a wrong assumption.

NOTE: i cleared the graph before running each of these

1

1 Answers

2
votes

You absolutely want to use an iterative loop still, because then the DB only has to parse a single CREATE statement and re-use it (iteration is native to Java, so it's easy to translate a request to iterate to fast queries). If you need to assign properties to each relationship, unwind the list of properties instead of the RANGE().

UNWIND {r_props} AS r_prop
CREATE (f) - [r:Qux] -> (b)
SET r = r_prop

Or if you need to calculate properties per-relationship based on a query, unwind the RANGE and you can do the full set of Cypher operations (MATCH, etc.) per relationship:

UNWIND range(0, 999) AS i
CREATE (f) - [r:Qux] -> (b)
MATCH (n:OtherNode {id: i})
SET r = PROPERTIES(n)

Using FOREACH is convenient but can be limiting. You'll still want an iterative loop either way, though, because it's always going to be quicker for neo4j to interpret.