16.4. Row operators

These operators take rows produced by another operator and transform them to a different set of rows

Eager

For isolation purposes this operator makes sure that operations that affect subsequent operations are executed fully for the whole dataset before continuing execution. Otherwise it could trigger endless loops, matching data again, that was just created. The Eager operator can cause high memory usage when importing data or migrating graph structures. In such cases split up your operations into simpler steps e.g. you can import nodes and relationships separately. Alternatively return the records to be updated and run an update statement afterwards.

Query 

MATCH (a)-[r]-(b)
DELETE r,a,b
MERGE ()

Query Plan 

+-------------------------+----------------+------+---------+---------------------+--------------+
| Operator                | Estimated Rows | Rows | DB Hits | Variables           | Other        |
+-------------------------+----------------+------+---------+---------------------+--------------+
| +ProduceResults         |              1 |    0 |       0 |                     |              |
| |                       +----------------+------+---------+---------------------+--------------+
| +EmptyResult            |                |    0 |       0 |                     |              |
| |                       +----------------+------+---------+---------------------+--------------+
| +Apply                  |              1 |  504 |       0 | a, b, r -- anon[38] |              |
| |\                      +----------------+------+---------+---------------------+--------------+
| | +AntiConditionalApply |              1 |  504 |       0 | anon[38]            |              |
| | |\                    +----------------+------+---------+---------------------+--------------+
| | | +MergeCreateNode    |              1 |    0 |       0 | anon[38]            |              |
| | |                     +----------------+------+---------+---------------------+--------------+
| | +Optional             |             35 |  504 |       0 | anon[38]            |              |
| | |                     +----------------+------+---------+---------------------+--------------+
| | +AllNodesScan         |             35 |  504 |     540 | anon[38]            |              |
| |                       +----------------+------+---------+---------------------+--------------+
| +Eager                  |                |   36 |       0 | a, b, r             |              |
| |                       +----------------+------+---------+---------------------+--------------+
| +Delete(3)              |             36 |   36 |      39 | a, b, r             |              |
| |                       +----------------+------+---------+---------------------+--------------+
| +Eager                  |                |   36 |       0 | a, b, r             |              |
| |                       +----------------+------+---------+---------------------+--------------+
| +Expand(All)            |             36 |   36 |      71 | a, r -- b           | (b)-[r:]-(a) |
| |                       +----------------+------+---------+---------------------+--------------+
| +AllNodesScan           |             35 |   35 |      36 | b                   |              |
+-------------------------+----------------+------+---------+---------------------+--------------+

Total database accesses: 686

Distinct

Removes duplicate rows from the incoming stream of rows.

Query 

MATCH (l:Location)<-[:WORKS_IN]-(p:Person)
RETURN DISTINCT l

Query Plan 

+------------------+----------------+------+---------+------------------+----------------------+
| Operator         | Estimated Rows | Rows | DB Hits | Variables        | Other                |
+------------------+----------------+------+---------+------------------+----------------------+
| +ProduceResults  |             14 |    6 |       0 | l                | l                    |
| |                +----------------+------+---------+------------------+----------------------+
| +Distinct        |             14 |    6 |       0 | l                | l                    |
| |                +----------------+------+---------+------------------+----------------------+
| +Filter          |             15 |   15 |      15 | anon[19], l, p   | p:Person             |
| |                +----------------+------+---------+------------------+----------------------+
| +Expand(All)     |             15 |   15 |      25 | anon[19], p -- l | (l)<-[:WORKS_IN]-(p) |
| |                +----------------+------+---------+------------------+----------------------+
| +NodeByLabelScan |             10 |   10 |      11 | l                | :Location            |
+------------------+----------------+------+---------+------------------+----------------------+

Total database accesses: 51

Eager Aggregation

Eagerly loads underlying results and stores it in a hash-map, using the grouping keys as the keys for the map.

Query 

MATCH (l:Location)<-[:WORKS_IN]-(p:Person)
RETURN l.name AS location, COLLECT(p.name) AS people

Query Plan 

+-------------------+----------------+------+---------+----------------------------+----------------------+
| Operator          | Estimated Rows | Rows | DB Hits | Variables                  | Other                |
+-------------------+----------------+------+---------+----------------------------+----------------------+
| +ProduceResults   |              4 |    6 |       0 | location, people           | location, people     |
| |                 +----------------+------+---------+----------------------------+----------------------+
| +EagerAggregation |              4 |    6 |      15 | people -- location         | location             |
| |                 +----------------+------+---------+----------------------------+----------------------+
| +Projection       |             15 |   15 |      15 | location -- anon[19], l, p | l.name; p            |
| |                 +----------------+------+---------+----------------------------+----------------------+
| +Filter           |             15 |   15 |      15 | anon[19], l, p             | p:Person             |
| |                 +----------------+------+---------+----------------------------+----------------------+
| +Expand(All)      |             15 |   15 |      25 | anon[19], p -- l           | (l)<-[:WORKS_IN]-(p) |
| |                 +----------------+------+---------+----------------------------+----------------------+
| +NodeByLabelScan  |             10 |   10 |      11 | l                          | :Location            |
+-------------------+----------------+------+---------+----------------------------+----------------------+

Total database accesses: 81

Node Count From Count Store

Use the count store to answer questions about node counts. This is much faster than eager aggregation which achieves the same result by actually counting. However the count store only saves a limited range of combinations, so eager aggregation will still be used for more complex queries. For example, we can get counts for all nodes, and nodes with a label, but not nodes with more than one label.

Query 

MATCH (p:Person)
RETURN count(p) AS people

Query Plan 

+--------------------------+----------------+------+---------+-----------+------------------------------+
| Operator                 | Estimated Rows | Rows | DB Hits | Variables | Other                        |
+--------------------------+----------------+------+---------+-----------+------------------------------+
| +ProduceResults          |              4 |    1 |       0 | people    | people                       |
| |                        +----------------+------+---------+-----------+------------------------------+
| +NodeCountFromCountStore |              4 |    1 |       0 | people    | count( (:Person) ) AS people |
+--------------------------+----------------+------+---------+-----------+------------------------------+

Total database accesses: 0

Relationship Count From Count Store

Use the count store to answer questions about relationship counts. This is much faster than eager aggregation which achieves the same result by actually counting. However the count store only saves a limited range of combinations, so eager aggregation will still be used for more complex queries. For example, we can get counts for all relationships, relationships with a type, relationships with a label on one end, but not relationships with labels on both end nodes.

Query 

MATCH (p:Person)-[r:WORKS_IN]->()
RETURN count(r) AS jobs

Query Plan 

+----------------------------------+----------------+------+---------+-----------+--------------------------------------------+
| Operator                         | Estimated Rows | Rows | DB Hits | Variables | Other                                      |
+----------------------------------+----------------+------+---------+-----------+--------------------------------------------+
| +ProduceResults                  |              4 |    1 |       0 | jobs      | jobs                                       |
| |                                +----------------+------+---------+-----------+--------------------------------------------+
| +RelationshipCountFromCountStore |              4 |    1 |       1 | jobs      | count( (:Person)-[:WORKS_IN]->() ) AS jobs |
+----------------------------------+----------------+------+---------+-----------+--------------------------------------------+

Total database accesses: 1

Filter

Filters each row coming from the child operator, only passing through rows that evaluate the predicates to TRUE.

Query 

MATCH (p:Person)
WHERE p.name =~ "^a.*"
RETURN p

Query Plan 

+------------------+----------------+------+---------+-----------+-----------------------------+
| Operator         | Estimated Rows | Rows | DB Hits | Variables | Other                       |
+------------------+----------------+------+---------+-----------+-----------------------------+
| +ProduceResults  |             14 |    0 |       0 | p         | p                           |
| |                +----------------+------+---------+-----------+-----------------------------+
| +Filter          |             14 |    0 |      14 | p         | p.name ~= /{  AUTOSTRING0}/ |
| |                +----------------+------+---------+-----------+-----------------------------+
| +NodeByLabelScan |             14 |   14 |      15 | p         | :Person                     |
+------------------+----------------+------+---------+-----------+-----------------------------+

Total database accesses: 29

Limit

Returns the first n rows from the incoming input.

Query 

MATCH (p:Person)
RETURN p
LIMIT 3

Query Plan 

+------------------+----------------+------+---------+-----------+------------+
| Operator         | Estimated Rows | Rows | DB Hits | Variables | Other      |
+------------------+----------------+------+---------+-----------+------------+
| +ProduceResults  |              3 |    3 |       0 | p         | p          |
| |                +----------------+------+---------+-----------+------------+
| +Limit           |              3 |    3 |       0 | p         | Literal(3) |
| |                +----------------+------+---------+-----------+------------+
| +NodeByLabelScan |             14 |    3 |       4 | p         | :Person    |
+------------------+----------------+------+---------+-----------+------------+

Total database accesses: 4

Projection

For each row from its input, projection evaluates a set of expressions and produces a row with the results of the expressions.

Query 

RETURN "hello" AS greeting

Query Plan 

+-----------------+----------------+------+---------+-----------+-----------------+
| Operator        | Estimated Rows | Rows | DB Hits | Variables | Other           |
+-----------------+----------------+------+---------+-----------+-----------------+
| +ProduceResults |              1 |    1 |       0 | greeting  | greeting        |
| |               +----------------+------+---------+-----------+-----------------+
| +Projection     |              1 |    1 |       0 | greeting  | {  AUTOSTRING0} |
+-----------------+----------------+------+---------+-----------+-----------------+

Total database accesses: 0

Skip

Skips n rows from the incoming rows

Query 

MATCH (p:Person)
RETURN p
ORDER BY p.id
SKIP 1

Query Plan 

+------------------+----------------+------+---------+----------------------------+-----------------------+
| Operator         | Estimated Rows | Rows | DB Hits | Variables                  | Other                 |
+------------------+----------------+------+---------+----------------------------+-----------------------+
| +ProduceResults  |             14 |   13 |       0 | p                          | p                     |
| |                +----------------+------+---------+----------------------------+-----------------------+
| +Projection      |             14 |   13 |       0 | p -- anon[35], anon[59], p | anon[35]              |
| |                +----------------+------+---------+----------------------------+-----------------------+
| +Skip            |             14 |   13 |       0 | anon[35], anon[59], p      | {  AUTOINT0}          |
| |                +----------------+------+---------+----------------------------+-----------------------+
| +Sort            |             14 |   14 |       0 | anon[35], anon[59], p      | anon[59]              |
| |                +----------------+------+---------+----------------------------+-----------------------+
| +Projection      |             14 |   14 |      28 | anon[59] -- anon[35], p    | anon[35]; anon[35].id |
| |                +----------------+------+---------+----------------------------+-----------------------+
| +Projection      |             14 |   14 |       0 | anon[35] -- p              | p                     |
| |                +----------------+------+---------+----------------------------+-----------------------+
| +NodeByLabelScan |             14 |   14 |      15 | p                          | :Person               |
+------------------+----------------+------+---------+----------------------------+-----------------------+

Total database accesses: 43

Sort

Sorts rows by a provided key.

Query 

MATCH (p:Person)
RETURN p
ORDER BY p.name

Query Plan 

+------------------+----------------+------+---------+----------------------------+-------------------------+
| Operator         | Estimated Rows | Rows | DB Hits | Variables                  | Other                   |
+------------------+----------------+------+---------+----------------------------+-------------------------+
| +ProduceResults  |             14 |   14 |       0 | p                          | p                       |
| |                +----------------+------+---------+----------------------------+-------------------------+
| +Projection      |             14 |   14 |       0 | p -- anon[24], anon[37], p | anon[24]                |
| |                +----------------+------+---------+----------------------------+-------------------------+
| +Sort            |             14 |   14 |       0 | anon[24], anon[37], p      | anon[37]                |
| |                +----------------+------+---------+----------------------------+-------------------------+
| +Projection      |             14 |   14 |      14 | anon[37] -- anon[24], p    | anon[24]; anon[24].name |
| |                +----------------+------+---------+----------------------------+-------------------------+
| +Projection      |             14 |   14 |       0 | anon[24] -- p              | p                       |
| |                +----------------+------+---------+----------------------------+-------------------------+
| +NodeByLabelScan |             14 |   14 |      15 | p                          | :Person                 |
+------------------+----------------+------+---------+----------------------------+-------------------------+

Total database accesses: 29

Top

Returns the first n rows sorted by a provided key. The physical operator is called Top. Instead of sorting the whole input, only the top X rows are kept.

Query 

MATCH (p:Person)
RETURN p
ORDER BY p.name
LIMIT 2

Query Plan 

+------------------+----------------+------+---------+----------------------------+-------------------------+
| Operator         | Estimated Rows | Rows | DB Hits | Variables                  | Other                   |
+------------------+----------------+------+---------+----------------------------+-------------------------+
| +ProduceResults  |              2 |    2 |       0 | p                          | p                       |
| |                +----------------+------+---------+----------------------------+-------------------------+
| +Projection      |              2 |    2 |       0 | p -- anon[24], anon[37], p | anon[24]                |
| |                +----------------+------+---------+----------------------------+-------------------------+
| +Top             |              2 |    2 |       0 | anon[24], anon[37], p      | Literal(2); anon[37]    |
| |                +----------------+------+---------+----------------------------+-------------------------+
| +Projection      |             14 |   14 |      14 | anon[37] -- anon[24], p    | anon[24]; anon[24].name |
| |                +----------------+------+---------+----------------------------+-------------------------+
| +Projection      |             14 |   14 |       0 | anon[24] -- p              | p                       |
| |                +----------------+------+---------+----------------------------+-------------------------+
| +NodeByLabelScan |             14 |   14 |      15 | p                          | :Person                 |
+------------------+----------------+------+---------+----------------------------+-------------------------+

Total database accesses: 29

Union

Union concatenates the results from the right plan after the results of the left plan.

Query 

MATCH (p:Location)
RETURN p.name
UNION ALL MATCH (p:Country)
RETURN p.name

Query Plan 

+--------------------+----------------+------+---------+-------------+-----------+
| Operator           | Estimated Rows | Rows | DB Hits | Variables   | Other     |
+--------------------+----------------+------+---------+-------------+-----------+
| +ProduceResults    |             10 |   11 |       0 | p.name      | p.name    |
| |                  +----------------+------+---------+-------------+-----------+
| +Union             |             10 |   11 |       0 | p.name      |           |
| |\                 +----------------+------+---------+-------------+-----------+
| | +Projection      |              1 |    1 |       1 | p.name -- p | p.name    |
| | |                +----------------+------+---------+-------------+-----------+
| | +NodeByLabelScan |              1 |    1 |       2 | p           | :Country  |
| |                  +----------------+------+---------+-------------+-----------+
| +Projection        |             10 |   10 |      10 | p.name -- p | p.name    |
| |                  +----------------+------+---------+-------------+-----------+
| +NodeByLabelScan   |             10 |   10 |      11 | p           | :Location |
+--------------------+----------------+------+---------+-------------+-----------+

Total database accesses: 24

Unwind

Takes a list of values and returns one row per item in the list.

Query 

UNWIND range(1,5) AS value
RETURN value;

Query Plan 

+-----------------+----------------+------+---------+-----------+-------+
| Operator        | Estimated Rows | Rows | DB Hits | Variables | Other |
+-----------------+----------------+------+---------+-----------+-------+
| +ProduceResults |             10 |    5 |       0 | value     | value |
| |               +----------------+------+---------+-----------+-------+
| +Unwind         |             10 |    5 |       0 | value     |       |
| |               +----------------+------+---------+-----------+-------+
| +EmptyRow       |              1 |    1 |       0 |           |       |
+-----------------+----------------+------+---------+-----------+-------+

Total database accesses: 0

Call Procedure

Return all labels sorted by name

Query 

CALL db.labels()YIELD label
RETURN *
ORDER BY label

Query Plan 

+-----------------+----------------+------+---------+-----------+----------------------------------+
| Operator        | Estimated Rows | Rows | DB Hits | Variables | Other                            |
+-----------------+----------------+------+---------+-----------+----------------------------------+
| +ProduceResults |          10000 |    4 |       0 | label     | label                            |
| |               +----------------+------+---------+-----------+----------------------------------+
| +Sort           |          10000 |    4 |       0 | label     | label                            |
| |               +----------------+------+---------+-----------+----------------------------------+
| +ProcedureCall  |          10000 |    4 |       1 | label     | db.labels() :: (label :: String) |
| |               +----------------+------+---------+-----------+----------------------------------+
| +EmptyRow       |              1 |    1 |       0 |           |                                  |
+-----------------+----------------+------+---------+-----------+----------------------------------+

Total database accesses: 1