I am still trying to understand why I get a cartesian product warning for a certain format for a query in neo4j and not for another. This is how I set up my database:
CREATE (q:Form {version: "1.0"})
CREATE (q:Question {text: "Sector de la empresa", active: true})
I then tried the following query:
MATCH
(f:Form {version: "1.0"}),
(q:Question {text: "Sector de la empresa"})
CREATE (f)-[:asks]->(q)
RETURN f, q
However, I get the following warning:
This query builds a cartesian product between disconnected patterns.
If a part of a query contains multiple disconnected patterns,
this will build a cartesian product between all those parts.
This may produce a large amount of data and slow down query processing.
While occasionally intended, it may often be possible to reformulate the
query that avoids the use of this cross product, perhaps by adding a
relationship between the different parts or by using OPTIONAL MATCH
(identifier is: (q))
When I use the following query, it does not give me this warning:
MATCH (f:Form {version: "1.0"})
WITH f
(q:Question {text: "Sector de la empresa"})
CREATE (f)-[:asks]->(q)
RETURN f, q
nor when I use this query:
MATCH (f:Form {version: "1.0"})
MATCH (q:Question {text: "Sector de la empresa"})
CREATE (f)-[:asks]->(q)
RETURN f, q
I used this following article as a resource, but it still didn't fully answer my question: Why does neo4j warn: "This query builds a cartesian product between disconnected patterns"?
Why do I get a cartesian product for some formats of a query and not others? Also, I do not fully understand what a cartesian product warning is.
To connect them to each other you either need two foreaches (one nested in the other), or to UNWIND both lists back to rows. That would get you a cartesian product as a result, but without doing the extra work from the back-to-back matches, then you create your relationships.
Most computers display images as a raster of points called pixels that can be addressed by their coordinates. These coordinates are ordered pairs and hence elements of a Cartesian product.
A Cartesian product is the result of joining every row in one table with every row in another table. This occurs when there is no WHERE clause to restrict rows. While this is legitimate in some cases, most occurrences of a Cartesian product are mistakes.
An OPTIONAL MATCH matches patterns against your graph database, just like a MATCH does. The difference is that if no matches are found, OPTIONAL MATCH will use a null for missing parts of the pattern. OPTIONAL MATCH could be considered the Cypher equivalent of the outer join in SQL.
If you are MATCH
ing on two different labels without any relationships between them, then you'll get this warning. The reason is because if you do:
MATCH (a:Foo), (b:Bar)
It's Neo4j's job to find every possible combination of those two nodes. So for the first match of a
it will return a row for every match of b
, for the second match of a
it will again return a row for every match of b
, and so on. So you'll get (number of Foo nodes) x (number of Bar nodes)
total rows in your result. As your database grows this is really bad for performance.
I can see that you're filtering on version
for Form
and text
for Question
, so that would help. That may even give you just one Form
node and one Question
node. So as long as you have an index on the Form(version)
and Question(text)
the query should be quite quick. Neo4j can't tell (or at least, isn't currently implemented to be able to tell) how many rows are going to be returned, so it gives a warning saying that your query could be potentially slow.
Having read your question, for a second there, my cypher-world imploded - all three queries should involve a cartesian product.
Having checked (on both the console and a local DB - both version 3.3.0), turns out I'm sane - they do all involve a cartesian product:
Why there is only a warning in the first case (still in version 3.3.0 I have no clue - you simply need to run the planner to figure this out, and if this isn't firing the warning what does? Some dumb cypher logic?
Cypher queries are made of parts, each can be either update (write) or read.
As far as read parts are concerned, this is what happens:
If you have something like this:
(a {name:'Bill'})-->(b:Dog)
The plan might look something like this.
AllNodeScan
):
name == 'bill'
)-->
relationships:Dog
)The important thing is that whilst to find (a)
we need to scan each node. But we simply traverse the graph to find the (b)
s - no AllNodeScan
for the latter.
(There are variants of AllNodeScan
, see Starting Node Operators)
When your query is something like this:
MATCH (f:Form {version: "1.0"}), (q:Question {text: "Sector de la empresa"})
Neo is forced to do an AllNodeScan
for both f
and q
- There is no pattern to traverse between them. This can potentially create a result set of an f * q size, which could be huge.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With