Cypher Query
Language
Chicago Graph Database Meet-Up
Max De Marzi
Updated for Neo4j 2.x by Brian Underwood
What is Cypher?
• Graph Query Language for
Neo4j
• Aims to make querying simple
Motivation
Why Cypher?
• Existing Neo4j query mechanisms were
not simple enough
• Too verbose (Java API)
• Too prescriptive (Gremlin)
Motivation
SQL?
• Unable to express paths
• these are crucial for graph-based
reasoning
• Neo4j is schema/table free
Design Decisions
Pattern matching
Design Decisions
Pattern matching
A
B C
Design Decisions
Pattern matching
Design Decisions
Pattern matching
Design Decisions
Pattern matching
Design Decisions
Pattern matching
Design Decisions
ASCII-art patterns
() --> ()
Design Decisions
Directed relationship
(A) --> (B)
A B
Design Decisions
Undirected relationship
(A) -- (B)
A B
Design Decisions
specific relationships
A -[:LOVES]-> B
A BLOVE
S
Design Decisions
Joined paths
A --> B --> C
A B C
Design Decisions
multiple paths
A --> B --> C, A --> C
A
B C
A --> B --> C <-- A
Design Decisions
Variable length paths
A -[*]-> B
A B
A B
A B
...
Design Decisions
Familiar for SQL users
select
from
where
group
by
order by
match
where
return
MATCH
SELECT *
FROM people
WHERE people.firstName = “Max”
MATCH (max:Person {firstName: ‘Max’})
RETURN max
MATCH (max:Person)
WHERE max.firstName = ‘Max’
RETURN max
MATCH
SELECT skills.*
FROM users
JOIN skills ON users.id = skills.user_id
WHERE users.first_name = ‘Max’
MATCH (user:User {firstName: ‘Max’}) -->
(skill:Skill)
RETURN skill
OPTIONAL MATCH
SELECT skills.*
FROM users
LEFT JOIN skills ON users.id = skills.user_id
WHERE users.first_name = ‘Max’
MATCH (user:User {firstName: ‘Max’})
OPTIONAL MATCH user –-> (skill:Skill)
RETURN skill
SELECT skills.*, user_skill.*
FROM users
JOIN user_skill ON users.id = user_skill.user_id
JOIN skills ON user_skill.skill_id = skill.id
WHERE users.first_name = ‘Max’
MATCH (user:User {firstName: ‘Max’})-
[user_skill]-> (skill:Skill)
RETURN skill, user_skill
Indexes
Used as multiple starting points, not to
speed up any traversals
CREATE INDEX ON :User(name);
MATCH (a:User {name: ‘Max’})-[r:KNOWS]-b
RETURN ID(a), ID(b), r.weight;
Complicated Match
Some UGLY recursive self join on the
groups table
MATCH group <-[:BELONGS_TO*]- (max:Person
{name: ‘Max’})
RETURN group
Where
SELECT person.*
FROM person
WHERE person.age >32
OR person.hair = "bald"
MATCH (person:Person)
WHERE person.age > 32 OR person.hair =
"bald"
RETURN person
Return
SELECT people.name, count(*)
FROM people
GROUP BY people.name
ORDER BY people.name
MATCH (person:Person)
RETURN person.name, count(*)
ORDER BY person.name
Order By, Parameters
Same as SQL
{node_id} expected as part of request
MATCH (me)-[:follows]->(friends)-[:follows]->(fof)-[:follows]->(fofof)-
[:follows]->others
WHERE ID(me) = {node_id}
RETURN me.name, friends.name, fof.name, fofof.name, count(others)
ORDER BY friends.name, fof.name, fofof.name, count(others) DESC
Graph Functions
Some UGLY multiple recursive self and inner joins
on the user and all related tables
MATCH p = shortestPath( lucy-[*]-kevin )
WHERE ID(lucy) = 1000 AND ID(kevin) = 759
RETURN p
Aggregate FunctionsID: get the neo4j assigned identifier
Count: add up the number of occurrences
Min: get the lowest value
Max: get the highest value
Avg: get the average of a numeric value
Distinct: remove duplicates
MATCH (me:User)-[r:wrote]-()
RETURN ID(me), me.name, count(r), min(r.date), max(r.date)
ORDER BY ID(me)
Functions
Collect: put aggregated values in a list
MATCH (a:User)-[:follows]->b
RETURN a.name, collect(b.name)
Each result row contains a name for each user
and a list of names which that user follows
Combine Functions
Collect the ID of friends
MATCH (me:User)<-[r:wrote]-(friends)
RETURN ID(me), me.name, collect(ID(friends)), collect(r.date)
ORDER BY ID(me)
Uses
Recommend Friends
MATCH (me)-[:friends]->(friend)-[:friends]->(foaf)
WHERE ID(me) = {node_id}
RETURN foaf.name
Uses
Six Degrees of Kevin Bacon
MATCH path = allShortestPaths( me-[*]->them )
WHERE ID(me) = {start_node_id}
AND ID(them) = {destination_node_id}
RETURN length(path),
extract(person in nodes(path) : person.name)
Length: counts the number of nodes along a path
Extract: gets the nodes/relationships from a path
http://thought-bytes.blogspot.com/2012/02/similarity-
based-recommendations-with.html
MATCH (me:User {id: {me_id}}), (similarUser:User),
(similarUsers)-[r:RATED]->(item)
WHERE ID(similarUser) IN {previousResult) AND
r.rating > 7 AND NOT((me)-[:RATED]->(item))
RETURN item
Items with a rating > 7 that similar users rated, but I have not
And: this and that are true
Or: this or that is true
Not: this is false
Boolean Operations
START london = node(1), moscow = node(2)
MATCH path = london -[*]-> moscow
WHERE all(city in nodes(path) where city.capital = true)
Predicates
ALL: closure is true for all items
ANY: closure is true for any item
NONE: closure is true for no items
SINGLE: closure is true for exactly 1 item
Thanks for Listening!
Questions?
maxdemarzi.com
Top Related