Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cypher / Should I use the WITH clause to pass values to next MATCH?

Tags:

neo4j

cypher

Using Neo4j 2.1.X, let's suppose this query, returning the user 123's friends that bought a Car:

MATCH (u1:User("123"))-[:KNOWS]-(friend)
MATCH (friend)-[:BUYS]->(c:Car)
RETURN friend

In this article, it is written regarding the WITH clause:

So, how does it work? Well, with is basically just a stream, as lazy as it can be (as lazy as return can be), passing results on to the next query.

So it seems I should transform the query like this:

MATCH (u1:User("123"))-[:KNOWS]-(friend)
WITH friend
MATCH (friend)-[:BUYS]->(c:Car)
RETURN friend

Should I? Or does the current version of Cypher already handle MATCH chaining while passing values through them?

like image 832
Mik378 Avatar asked Jan 10 '23 14:01

Mik378


1 Answers

The more accurate starting point you give in the upfront of your query, the more efficient it will be.

Your first match is not so accurate, indeed it will use the traversal matcher to match all possible relationships.

Taken the following neo4j console example : http://console.neo4j.org/r/jsx71g

And your first query who will look like this in the example :

MATCH (n:User { login: 'nash99' })-[:KNOWS]->(friend)
RETURN count(*)

You can see the amount of dbhits in the upfront :

    Execution Plan

    ColumnFilter
      |
      +EagerAggregation
        |
        +Filter
          |
          +TraversalMatcher

    +------------------+------+--------+-------------+-----------------------------------------+
    |         Operator | Rows | DbHits | Identifiers |                                   Other |
    +------------------+------+--------+-------------+-----------------------------------------+
    |     ColumnFilter |    1 |      0 |             |                   keep columns count(*) |
    | EagerAggregation |    1 |      0 |             |                                         |
    |           Filter |    8 |    320 |             | Property(n,login(2)) == {  AUTOSTRING0} |
    | TraversalMatcher |  160 |    201 |             |             friend,   UNNAMED32, friend |
    +------------------+------+--------+-------------+-----------------------------------------+
Total database accesses: 521

If you use a more accurate starting point, you're the king of the road when you start from this point, look at this example query and see the difference in db hits :

Execution Plan

ColumnFilter
  |
  +EagerAggregation
    |
    +SimplePatternMatcher
      |
      +Filter
        |
        +NodeByLabel

+----------------------+------+--------+------------------------+-----------------------------------------+
|             Operator | Rows | DbHits |            Identifiers |                                   Other |
+----------------------+------+--------+------------------------+-----------------------------------------+
|         ColumnFilter |    1 |      0 |                        |                   keep columns count(*) |
|     EagerAggregation |    1 |      0 |                        |                                         |
| SimplePatternMatcher |    8 |      0 | n, friend,   UNNAMED51 |                                         |
|               Filter |    1 |     40 |                        | Property(n,login(2)) == {  AUTOSTRING0} |
|          NodeByLabel |   20 |     21 |                   n, n |                                   :User |
+----------------------+------+--------+------------------------+-----------------------------------------+

Total database accesses: 61

So to terminate your query, I will do something like this :

MATCH (n:User { login: 'nash99' })
WITH n
MATCH (n)-[:KNOWS]->(friend)-[:BUYS]->(c:Car)
RETURN friend

You can also specify that the friends can not be the same as the user :

MATCH (n:User { login: 'nash99' })
    WITH n
    MATCH (n)-[:KNOWS]->(friend)-[:BUYS]->(c:Car)
    WHERE NOT friend.id = n.id
    RETURN friend

Note that there is no difference between the above query and the following in matter of db hits :

MATCH (n:User { login: 'nash99' })
WITH n
MATCH (n)-[:KNOWS]->(friend)
WITH friend
MATCH (friend)-[:BUYS)->(c:Car)
RETURN (friend)

I recommend that you use the neo4j console to look at the result details showing you the above informations.

If you need to quickly protoype a graph for test, you can use Graphgen, export the graph in cypher statements and load these statements in the neo4j console.

Here is the link to the graphgen generation I used for the console http://graphgen.neoxygen.io/?graph=29l9XJ0HxJ2pyQ

Chris

like image 146
Christophe Willemsen Avatar answered Feb 08 '23 13:02

Christophe Willemsen