The combining operators are used to piece together other operators.
The following graph is used for the examples below:
Apply
Apply
works by performing a nested loop.
Every row being produced on the left-hand side of the Apply
operator will be fed to the leaf
operator on the right-hand side, and then Apply
will yield the combined results.
Apply
, being a nested loop, can be seen as a warning that a better plan was not found.
Query
MATCH (p:Person)-[:FRIENDS_WITH]->(f) WITH p, count(f) AS fs WHERE fs > 2 OPTIONAL MATCH (p)-[:WORKS_IN]->(city) RETURN city.name
Finds all the people with more than two friends and returns the city they work in.
Query plan
+----------------------+----------------+----------------------------------------------+--------------------------+ | Operator | Estimated Rows | Variables | Other | +----------------------+----------------+----------------------------------------------+--------------------------+ | +ProduceResults | 1 | city.name | city.name | | | +----------------+----------------------------------------------+--------------------------+ | +Projection | 1 | city.name -- anon[70], anon[93], city, fs, p | city.name | | | +----------------+----------------------------------------------+--------------------------+ | +OptionalExpand(All) | 1 | anon[93], city -- anon[70], fs, p | (p)-[:WORKS_IN]->(city) | | | +----------------+----------------------------------------------+--------------------------+ | +Filter | 1 | anon[70], fs, p | anon[70] | | | +----------------+----------------------------------------------+--------------------------+ | +Projection | 1 | anon[70] -- fs, p | p; fs; fs > { AUTOINT0} | | | +----------------+----------------------------------------------+--------------------------+ | +EagerAggregation | 1 | fs -- p | p | | | +----------------+----------------------------------------------+--------------------------+ | +Expand(All) | 2 | anon[17], f -- p | (p)-[:FRIENDS_WITH]->(f) | | | +----------------+----------------------------------------------+--------------------------+ | +NodeByLabelScan | 14 | p | :Person | +----------------------+----------------+----------------------------------------------+--------------------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MATCH (p:Person)-[:FRIENDS_WITH]->(f) WITH p, count(f) as fs WHERE fs > 2 OPTIONAL MATCH (p)-[:WORKS_IN]->(city) RETURN city.name
SemiApply
Tests for the existence of a pattern predicate.
SemiApply
takes a row from its child operator and feeds it to the leaf operator on the right-hand side.
If the right-hand side operator tree yields at least one row, the row from the
left-hand side is yielded by the SemiApply
operator.
This makes SemiApply
a filtering operator, used mostly for pattern predicates in queries.
Query
MATCH (p:Person) WHERE (p)-[:FRIENDS_WITH]->() RETURN p.name
Finds all the people who have friends.
Query plan
+------------------+----------------+-------------------------+-------------------------+ | Operator | Estimated Rows | Variables | Other | +------------------+----------------+-------------------------+-------------------------+ | +ProduceResults | 11 | p.name | p.name | | | +----------------+-------------------------+-------------------------+ | +Projection | 11 | p.name -- p | p.name | | | +----------------+-------------------------+-------------------------+ | +SemiApply | 11 | p | | | |\ +----------------+-------------------------+-------------------------+ | | +Expand(All) | 2 | anon[27], anon[45] -- p | (p)-[:FRIENDS_WITH]->() | | | | +----------------+-------------------------+-------------------------+ | | +Argument | 14 | p | | | | +----------------+-------------------------+-------------------------+ | +NodeByLabelScan | 14 | p | :Person | +------------------+----------------+-------------------------+-------------------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MATCH (p:Person) WHERE (p)-[:FRIENDS_WITH]->() RETURN p.name
AntiSemiApply
Tests for the existence of a pattern predicate.
SemiApply
takes a row from its child operator and feeds it to the leaf operator on the right-hand side.
If the right-hand side operator tree yields at least one row, the row from the
left-hand side is yielded by the SemiApply
operator.
This makes SemiApply
a filtering operator, used mostly for pattern predicates in queries.
Query
MATCH (me:Person { name: "me" }),(other:Person) WHERE NOT (me)-[:FRIENDS_WITH]->(other) RETURN other.name
Finds the names of all the people who are not my friends.
Query plan
+--------------------+----------------+-------------------------+-------------------------------+ | Operator | Estimated Rows | Variables | Other | +--------------------+----------------+-------------------------+-------------------------------+ | +ProduceResults | 4 | other.name | other.name | | | +----------------+-------------------------+-------------------------------+ | +Projection | 4 | other.name -- me, other | other.name | | | +----------------+-------------------------+-------------------------------+ | +AntiSemiApply | 4 | me, other | | | |\ +----------------+-------------------------+-------------------------------+ | | +Expand(Into) | 0 | anon[62] -- me, other | (me)-[:FRIENDS_WITH]->(other) | | | | +----------------+-------------------------+-------------------------------+ | | +Argument | 14 | me, other | | | | +----------------+-------------------------+-------------------------------+ | +CartesianProduct | 14 | me -- other | | | |\ +----------------+-------------------------+-------------------------------+ | | +NodeByLabelScan | 14 | other | :Person | | | +----------------+-------------------------+-------------------------------+ | +NodeIndexSeek | 1 | me | :Person(name) | +--------------------+----------------+-------------------------+-------------------------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MATCH (me:Person {name: "me"}), (other:Person) WHERE NOT (me)-[:FRIENDS_WITH]->(other) RETURN other.name
LetSemiApply
Tests for the existence of a pattern predicate.
When a query contains multiple pattern predicates LetSemiApply
will be used to evaluate the first of these.
It will record the result of evaluating the predicate but will leave any filtering to a another operator.
Query
MATCH (other:Person) WHERE (other)-[:FRIENDS_WITH]->() OR (other)-[:WORKS_IN]->() RETURN other.name
Finds the names of all the people who have a friend or who work somewhere.
The LetSemiApply
operator will be used to check for the existence of the FRIENDS_WITH
relationship from each person.
Query plan
+--------------------+----------------+-------------------------------+-----------------------------+ | Operator | Estimated Rows | Variables | Other | +--------------------+----------------+-------------------------------+-----------------------------+ | +ProduceResults | 13 | other.name | other.name | | | +----------------+-------------------------------+-----------------------------+ | +Projection | 13 | other.name -- anon[27], other | other.name | | | +----------------+-------------------------------+-----------------------------+ | +SelectOrSemiApply | 13 | anon[27] -- other | anon[27] | | |\ +----------------+-------------------------------+-----------------------------+ | | +Expand(All) | 15 | anon[66], anon[80] -- other | (other)-[:WORKS_IN]->() | | | | +----------------+-------------------------------+-----------------------------+ | | +Argument | 14 | other | | | | +----------------+-------------------------------+-----------------------------+ | +LetSemiApply | 14 | anon[27] -- other | | | |\ +----------------+-------------------------------+-----------------------------+ | | +Expand(All) | 2 | anon[35], anon[53] -- other | (other)-[:FRIENDS_WITH]->() | | | | +----------------+-------------------------------+-----------------------------+ | | +Argument | 14 | other | | | | +----------------+-------------------------------+-----------------------------+ | +NodeByLabelScan | 14 | other | :Person | +--------------------+----------------+-------------------------------+-----------------------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MATCH (other:Person) WHERE (other)-[:FRIENDS_WITH]->() OR (other)-[:WORKS_IN]->() RETURN other.name
LetAntiSemiApply
Tests for the absence of a pattern predicate.
When a query contains multiple pattern predicates LetAntiSemiApply
will be used to evaluate the first of these.
It will record the result of evaluating the predicate but will leave any filtering to another operator.
The following query will find all the people who don’t have any friends or who work somewhere.
Query
MATCH (other:Person) WHERE NOT ((other)-[:FRIENDS_WITH]->()) OR (other)-[:WORKS_IN]->() RETURN other.name
Finds all the people who don’t have any friends or who work somewhere.
The LetAntiSemiApply
operator will be used to check for the absence of
the FRIENDS_WITH
relationship from each person.
Query plan
+--------------------+----------------+-------------------------------+-----------------------------+ | Operator | Estimated Rows | Variables | Other | +--------------------+----------------+-------------------------------+-----------------------------+ | +ProduceResults | 11 | other.name | other.name | | | +----------------+-------------------------------+-----------------------------+ | +Projection | 11 | other.name -- anon[31], other | other.name | | | +----------------+-------------------------------+-----------------------------+ | +SelectOrSemiApply | 11 | anon[31] -- other | anon[31] | | |\ +----------------+-------------------------------+-----------------------------+ | | +Expand(All) | 15 | anon[71], anon[85] -- other | (other)-[:WORKS_IN]->() | | | | +----------------+-------------------------------+-----------------------------+ | | +Argument | 14 | other | | | | +----------------+-------------------------------+-----------------------------+ | +LetAntiSemiApply | 14 | anon[31] -- other | | | |\ +----------------+-------------------------------+-----------------------------+ | | +Expand(All) | 2 | anon[39], anon[57] -- other | (other)-[:FRIENDS_WITH]->() | | | | +----------------+-------------------------------+-----------------------------+ | | +Argument | 14 | other | | | | +----------------+-------------------------------+-----------------------------+ | +NodeByLabelScan | 14 | other | :Person | +--------------------+----------------+-------------------------------+-----------------------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MATCH (other:Person) WHERE NOT((other)-[:FRIENDS_WITH]->()) OR (other)-[:WORKS_IN]->() RETURN other.name
SelectOrSemiApply
Tests for the existence of a pattern predicate and evaluates a predicate.
This operator allows for the mixing of normal predicates and pattern predicates
that check for the existence of a pattern.
First the normal expression predicate is evaluated, and only if it returns false
the costly pattern predicate evaluation is performed.
Query
MATCH (other:Person) WHERE other.age > 25 OR (other)-[:FRIENDS_WITH]->() RETURN other.name
Finds the names of all people who have friends, or are older than 25.
Query plan
+--------------------+----------------+-----------------------------+-----------------------------+ | Operator | Estimated Rows | Variables | Other | +--------------------+----------------+-----------------------------+-----------------------------+ | +ProduceResults | 11 | other.name | other.name | | | +----------------+-----------------------------+-----------------------------+ | +Projection | 11 | other.name -- other | other.name | | | +----------------+-----------------------------+-----------------------------+ | +SelectOrSemiApply | 11 | other | other.age > { AUTOINT0} | | |\ +----------------+-----------------------------+-----------------------------+ | | +Expand(All) | 2 | anon[53], anon[71] -- other | (other)-[:FRIENDS_WITH]->() | | | | +----------------+-----------------------------+-----------------------------+ | | +Argument | 14 | other | | | | +----------------+-----------------------------+-----------------------------+ | +NodeByLabelScan | 14 | other | :Person | +--------------------+----------------+-----------------------------+-----------------------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MATCH (other:Person) WHERE other.age > 25 OR (other)-[:FRIENDS_WITH]->() RETURN other.name
SelectOrAntiSemiApply
Tests for the absence of a pattern predicate and evaluates a predicate.
Query
MATCH (other:Person) WHERE other.age > 25 OR NOT (other)-[:FRIENDS_WITH]->() RETURN other.name
Finds the names of all people who do not have friends, or are older than 25.
Query plan
+------------------------+----------------+-----------------------------+-----------------------------+ | Operator | Estimated Rows | Variables | Other | +------------------------+----------------+-----------------------------+-----------------------------+ | +ProduceResults | 4 | other.name | other.name | | | +----------------+-----------------------------+-----------------------------+ | +Projection | 4 | other.name -- other | other.name | | | +----------------+-----------------------------+-----------------------------+ | +SelectOrAntiSemiApply | 4 | other | other.age > { AUTOINT0} | | |\ +----------------+-----------------------------+-----------------------------+ | | +Expand(All) | 2 | anon[57], anon[75] -- other | (other)-[:FRIENDS_WITH]->() | | | | +----------------+-----------------------------+-----------------------------+ | | +Argument | 14 | other | | | | +----------------+-----------------------------+-----------------------------+ | +NodeByLabelScan | 14 | other | :Person | +------------------------+----------------+-----------------------------+-----------------------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MATCH (other:Person) WHERE other.age > 25 OR NOT (other)-[:FRIENDS_WITH]->() RETURN other.name
ConditionalApply
Checks whether a variable is not null
, and if so the right-hand side will be executed.
Query
MERGE (p:Person { name: 'Andres' }) ON MATCH SET p.exists = TRUE
Looks for the existence of a person called Andres, and if found sets the exists
property to true
.
Query plan
+-----------------------+----------------+-----------+---------------+ | Operator | Estimated Rows | Variables | Other | +-----------------------+----------------+-----------+---------------+ | +ProduceResults | 1 | | | | | +----------------+-----------+---------------+ | +EmptyResult | | | | | | +----------------+-----------+---------------+ | +AntiConditionalApply | 1 | p | | | |\ +----------------+-----------+---------------+ | | +MergeCreateNode | 1 | p | | | | +----------------+-----------+---------------+ | +ConditionalApply | 1 | p | | | |\ +----------------+-----------+---------------+ | | +SetNodeProperty | 1 | p | | | | | +----------------+-----------+---------------+ | | +Argument | 1 | p | | | | +----------------+-----------+---------------+ | +Optional | 1 | p | | | | +----------------+-----------+---------------+ | +NodeIndexSeek | 1 | p | :Person(name) | +-----------------------+----------------+-----------+---------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MERGE (p:Person {name: 'Andres'}) ON MATCH SET p.exists = true
AntiConditionalApply
Checks whether a variable is null
, and if so the right-hand side will be executed.
Query
MERGE (p:Person { name: 'Andres' }) ON CREATE SET p.exists = TRUE
Looks for the existence of a person called Andres, and if not found, creates one and
sets the exists
property to true
.
Query plan
+-----------------------+----------------+-----------+---------------+ | Operator | Estimated Rows | Variables | Other | +-----------------------+----------------+-----------+---------------+ | +ProduceResults | 1 | | | | | +----------------+-----------+---------------+ | +EmptyResult | | | | | | +----------------+-----------+---------------+ | +AntiConditionalApply | 1 | p | | | |\ +----------------+-----------+---------------+ | | +SetNodeProperty | 1 | p | | | | | +----------------+-----------+---------------+ | | +MergeCreateNode | 1 | p | | | | +----------------+-----------+---------------+ | +Optional | 1 | p | | | | +----------------+-----------+---------------+ | +NodeIndexSeek | 1 | p | :Person(name) | +-----------------------+----------------+-----------+---------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MERGE (p:Person {name: 'Andres'}) ON CREATE SET p.exists = true
AssertSameNode
This operator is used to ensure that no uniqueness constraints are violated.
Query
MERGE (t:Team { name: 'Engineering', id: 42 })
Looks for the existence of a team with the supplied name and id, and if one does not exist,
it will be created. Due to the existence of two uniqueness constraints
on :Team(name)
and :Team(id)
, any node that would be found by the `UniqueIndexSeek`s
must be the very same node, or the constraints would be violated.
Query plan
+---------------------------------+----------------+-----------+-------------+ | Operator | Estimated Rows | Variables | Other | +---------------------------------+----------------+-----------+-------------+ | +ProduceResults | 1 | | | | | +----------------+-----------+-------------+ | +EmptyResult | | | | | | +----------------+-----------+-------------+ | +AntiConditionalApply | 1 | t | | | |\ +----------------+-----------+-------------+ | | +MergeCreateNode | 1 | t | | | | +----------------+-----------+-------------+ | +Optional | 1 | t | | | | +----------------+-----------+-------------+ | +AssertSameNode | 0 | t | | | |\ +----------------+-----------+-------------+ | | +NodeUniqueIndexSeek(Locking) | 1 | t | :Team(id) | | | +----------------+-----------+-------------+ | +NodeUniqueIndexSeek(Locking) | 1 | t | :Team(name) | +---------------------------------+----------------+-----------+-------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MERGE (t:Team {name: 'Engineering', id: 42})
NodeHashJoin
Using a hash table, a NodeHashJoin
joins the input coming from the left with the input coming from the right.
Query
MATCH (andy:Person { name:'Andreas' })-[:WORKS_IN]->(loc)<-[:WORKS_IN]-(matt:Person { name:'Mattis' }) RETURN loc.name
Returns the name of the location where the matched persons both work.
Query plan
+------------------+----------------+-------------------------------------------------+---------------------------+ | Operator | Estimated Rows | Variables | Other | +------------------+----------------+-------------------------------------------------+---------------------------+ | +ProduceResults | 10 | loc.name | loc.name | | | +----------------+-------------------------------------------------+---------------------------+ | +Projection | 10 | loc.name -- anon[37], anon[56], andy, loc, matt | loc.name | | | +----------------+-------------------------------------------------+---------------------------+ | +Filter | 10 | anon[37], anon[56], andy, loc, matt | NOT(anon[37] == anon[56]) | | | +----------------+-------------------------------------------------+---------------------------+ | +NodeHashJoin | 10 | anon[37], andy -- anon[56], loc, matt | loc | | |\ +----------------+-------------------------------------------------+---------------------------+ | | +Expand(All) | 19 | anon[56], loc -- matt | (matt)-[:WORKS_IN]->(loc) | | | | +----------------+-------------------------------------------------+---------------------------+ | | +NodeIndexSeek | 1 | matt | :Person(name) | | | +----------------+-------------------------------------------------+---------------------------+ | +Expand(All) | 19 | anon[37], loc -- andy | (andy)-[:WORKS_IN]->(loc) | | | +----------------+-------------------------------------------------+---------------------------+ | +NodeIndexSeek | 1 | andy | :Person(name) | +------------------+----------------+-------------------------------------------------+---------------------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MATCH (london:Location {name: 'London'}), (person:Person {name: 'Pontus'}) FOREACH(x in range(0,250) | CREATE (person)-[:WORKS_IN]->(london) ) MATCH (andy:Person {name:'Andreas'})-[:WORKS_IN]->(loc)<-[:WORKS_IN]-(matt:Person {name:'Mattis'}) RETURN loc.name
Triadic
Triadic is used to solve triangular queries, such as the very common find my friend-of-friends that are not already my friend. It does so by putting all the friends in a set, and use that set to check if the friend-of-friends are already connected to me.
Query
MATCH (me:Person)-[:FRIENDS_WITH]-()-[:FRIENDS_WITH]-(other) WHERE NOT (me)-[:FRIENDS_WITH]-(other) RETURN other.name
Finds the names of all friends of my friends that are not already my friends.
Query plan
+-------------------+----------------+-------------------------------------------------------+----------------------------+ | Operator | Estimated Rows | Variables | Other | +-------------------+----------------+-------------------------------------------------------+----------------------------+ | +ProduceResults | 0 | other.name | other.name | | | +----------------+-------------------------------------------------------+----------------------------+ | +Projection | 0 | other.name -- anon[18], anon[35], anon[37], me, other | other.name | | | +----------------+-------------------------------------------------------+----------------------------+ | +TriadicSelection | 0 | anon[18], anon[35], me -- anon[37], other | me, anon[35], other | | |\ +----------------+-------------------------------------------------------+----------------------------+ | | +Filter | 0 | anon[37], other | NOT(anon[18] == anon[37]) | | | | +----------------+-------------------------------------------------------+----------------------------+ | | +Expand(All) | 0 | anon[37], other | ()-[:FRIENDS_WITH]-(other) | | | | +----------------+-------------------------------------------------------+----------------------------+ | | +Argument | 4 | | | | | +----------------+-------------------------------------------------------+----------------------------+ | +Expand(All) | 4 | anon[18], anon[35] -- me | (me)-[:FRIENDS_WITH]-() | | | +----------------+-------------------------------------------------------+----------------------------+ | +NodeByLabelScan | 14 | me | :Person | +-------------------+----------------+-------------------------------------------------------+----------------------------+ Total database accesses: ?
Try this query live CREATE CONSTRAINT ON (team:Team) ASSERT team.name is UNIQUE CREATE CONSTRAINT ON (team:Team) ASSERT team.id is UNIQUE CREATE INDEX ON :Location(name) CREATE INDEX ON :Person(name) CREATE (me:Person {name:'me'}) CREATE (andres:Person {name:'Andres'}) CREATE (andreas:Person {name:'Andreas'}) CREATE (mattias:Person {name:'Mattias'}) CREATE (lovis:Person {name:'Lovis'}) CREATE (pontus:Person {name:'Pontus'}) CREATE (max:Person {name:'Max'}) CREATE (konstantin:Person {name:'Konstantin'}) CREATE (stefan:Person {name:'Stefan'}) CREATE (mats:Person {name:'Mats'}) CREATE (petra:Person {name:'Petra'}) CREATE (craig:Person {name:'Craig'}) CREATE (steven:Person {name:'Steven'}) CREATE (chris:Person {name:'Chris'}) CREATE (london:Location {name:'London'}) CREATE (malmo:Location {name:'Malmo'}) CREATE (sf:Location {name:'San Francisco'}) CREATE (berlin:Location {name:'Berlin'}) CREATE (newyork:Location {name:'New York'}) CREATE (kuala:Location {name:'Kuala Lumpur'}) CREATE (stockholm:Location {name:'Stockholm'}) CREATE (paris:Location {name:'Paris'}) CREATE (madrid:Location {name:'Madrid'}) CREATE (rome:Location {name:'Rome'}) CREATE (england:Country {name:'England'}) CREATE (field:Team {name:'Field'}) CREATE (engineering:Team {name:'Engineering', id: 42}) CREATE (sales:Team {name:'Sales'}) CREATE (monads:Team {name:'Team Monads'}) CREATE (birds:Team {name:'Team Enlightened Birdmen'}) CREATE (quality:Team {name:'Team Quality'}) CREATE (rassilon:Team {name:'Team Rassilon'}) CREATE (executive:Team {name:'Team Executive'}) CREATE (remoting:Team {name:'Team Remoting'}) CREATE (other:Team {name:'Other'}) CREATE (me)-[:WORKS_IN {duration: 190}]->(london) CREATE (andreas)-[:WORKS_IN {duration: 187}]->(london) CREATE (andres)-[:WORKS_IN {duration: 150}]->(london) CREATE (mattias)-[:WORKS_IN {duration: 230}]->(london) CREATE (lovis)-[:WORKS_IN {duration: 230}]->(sf) CREATE (pontus)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (max)-[:WORKS_IN {duration: 230}]->(newyork) CREATE (konstantin)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(london) CREATE (stefan)-[:WORKS_IN {duration: 230}]->(berlin) CREATE (mats)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (petra)-[:WORKS_IN {duration: 230}]->(london) CREATE (craig)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (steven)-[:WORKS_IN {duration: 230}]->(malmo) CREATE (chris)-[:WORKS_IN {duration: 230}]->(madrid) CREATE (london)-[:IN]->(england) CREATE (me)-[:FRIENDS_WITH]->(andres) CREATE (andres)-[:FRIENDS_WITH]->(andreas) MATCH (me:Person)-[:FRIENDS_WITH]-()-[:FRIENDS_WITH]-(other) WHERE NOT (me)-[:FRIENDS_WITH]-(other) RETURN other.name