Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

State of the Cypher UNION

DZone's Guide to

State of the Cypher UNION

· Java Zone
Free Resource

Try Okta to add social login, MFA, and OpenID Connect support to your Java app in minutes. Create a free developer account today and never build auth again.

Neo4j 2.0 introduced the UNION (ALL) clause, which can join the results of 2 or more complete statements into a single result. Each of the statements is fully formed and contains result projection and pagination.

You need to have the same amount and names of columns to be joined in an UNION. UNION by default returns the distinct set of results.

Using UNION ALL will return the full results (and will be faster and less memory intensive).

Here are two examples:

MATCH (d:Developer) RETURN d.name as name
UNION
MATCH (e:Employee) RETURN e.name as name

Most often UNION is not needed and can be alleviated by a different graph model or query structure, but we’ll return to that later.

During a conversation with a partner of ours we found a pitfall that you might run into too. Let’s have a look at their query.

START n=node:Person(name={name})
MATCH (n)-[:MANAGES]->()-[:HAS_SKILL]->(s) RETURN s.name as name
UNION
MATCH (n)-[:HAS_SKILL]->(s) RETURN s.name as name

Looks harmless, right? The problem was it returned too much (unrelated) data.

What happened here? As we said, UNION combines the outputs from two full statements. The two statements in this case are:

// statement one
START n=node:Person(name={name})
MATCH (n)-[:MANAGES]->()-[:HAS_SKILL]->(s) RETURN s.name as name

// statement two
MATCH (n)-[:HAS_SKILL]->(s) RETURN s.name as name

As you can see the first statement looks good, whereas the second is a full graph scan of the database, finding all HAS_SKILL relationships. Not what we want.

The direct solution would be to just fix that:

START n=node:Person(name={name})
MATCH (n)-[:MANAGES]->()-[:HAS_SKILL]->(s) RETURN s.name as name
UNION
START n=node:Person(name={name})
MATCH (n)-[:HAS_SKILL]->(s) RETURN s.name as name

But it is much easier to just change the query structure:

START n=node:Person(name={name})
MATCH (n)-[:MANAGES*0..1]->()-[:HAS_SKILL]->(s) RETURN s.name as name

or actually:

MATCH (n:Person {name:{name}})-[:MANAGES*0..1]->
()-[:HAS_SKILL]->(s) RETURN s.name as name

We now can even represent an arbitrary managment level structure.

MATCH (n:Person {name:{name}})-[:MANAGES*0..]->
()-[:HAS_SKILL]->(s) RETURN s.name as name

Build and launch faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:
java ,nosql ,architecture ,tips and tricks ,neo4j ,cypher ,union ,union all ,tools & methods

Published at DZone with permission of Michael Hunger, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}