In the first post of this series we looked at what a Graph DB is and why should you use one.
Today we'll learn what is Cypher start querying the graph!
What is Cypher
Cypher it's a declarative query language, developed internally by Neo4j since 2011.
There is an ongoing standardization process (OpenCypher) to make Cypher an open standard.
Cypher let's you easily retrieve data from the graph. It's one of the simplest query language to learn; its syntax is constructed in a way that helps visualize relationship between nodes
RedisInsight
We will be running queries in RedisInsight. If you've read the previous post of this series, you should know how to run a docker based installation of Redis.
After launching docker compose up -d
, point your browser to http://localhost:8001 , RedisInsight should welcome you. Accept the EULA and you will be redirected to RedisInsight dashboard.
Next click on the "Workbench" tab (the third icon in the side menu on the left).
The upper right pane of this new screen is where you'll write all the queries.
Adding nodes and edges
Now that both Redis and RedisInsight are up & running, let's create a new graph and add one node to it:
GRAPH.QUERY Social "CREATE (:Person {name: 'Laura Phillips', age: 32})"
Every query is prepended by GRAPH.QUERY
and the graph name.
Now click the green arrow to the right or press Ctrl + Enter
.
The output should be similar to this:
The first time we create e node in a non-existent graph, RedisGraph will create the graph for us.
So we've just created a new graph called "Social" and added one node of type "Person".
name
and age
are properties that we add to the node. RedisGrap automatically add another property to each node: the unique id
.
We can add more nodes in bulk:
GRAPH.QUERY Social "CREATE (:Person {name: 'Diana Hendrickson', age: 31}), (:Person {name: 'Susan Hendrickson', age: 29}), (:Person {name: 'Peter Steinmetz', age: 30}), (:Person {name: 'Louise Rosol', age: 29}), (:Person {name: 'Bryce Fett', age: 30})"
Now you should have 6 nodes of type Person
in the graph. Let's check them out!
Basic querying
GRAPH.QUERY Social "MATCH (p:Person) RETURN p"
Let's analyze this query: MATCH
is the keyword that describes the relationship between queried entities. It's used to 'match' something in the graph, based on some parameters. In this case we are asking for Person
, and we alias our results with a p
(the alias name is not important, you can choose any letter or word).
Nodes are always specified in round brackets.
The RETURN
keyword returns every p
found.
So this query returns every Person
it finds in the graph Social
.
The resulting graph should be something like this:
The previous query could also be written as:
GRAPH.QUERY Social "MATCH (a) RETURN a"
This is the generic way to view all nodes in the graph, you'll see this a lot of times. Here we are using an alias a
without asking for a specific node type.
Ok, so let's say we want to retrieve all Person(s) who are exactly 30 years old:
GRAPH.QUERY Social "MATCH (p:Person {age: 30}) RETURN p"
this query introduces another feature: match for node's attribute. Here we are matching only nodes of type Person
and with an attribute age
equal to 30
.
You can query for multiple attributes, by separating attribute: value
couples with comma between the curly brackets.
Sometimes visualizing a graph of this kind isn't much helpful, a textual result might be more useful.
So click on the </>
icon just above the last graph and choose Text
; the output of the last query will be shown as text:
Connecting nodes and creating edges
Now we add one relation between two nodes:
GRAPH.QUERY Social "MATCH (a:Person {name: 'Diana Hendrickson'}), (b:Person {name: 'Susan Hendrickson'}) CREATE (a)-[:KNOWS {relation: 'sister'}]->(b)"
The first part of the query is a MATCH to find 2 Person
('Diana Hendrickson' and 'Susan Hendrickson'); we alias them with a
and b
.
Then we create the relation:
CREATE (a)-[:KNOWS {relation: 'sister'}]->(b)
relationships are always written in square brackets. We are binding node a
and node b
with a relation of type KNOWS
. The KNOWS
relation has an attribute relation
with value sister
.
Redis is informing us that it has created one relationship with one properties.
NOTE: The correct way to add a relation between existent nodes is by matching them first; if we try to directly create the relationship, like so:
CREATE (a:Person {name: 'Diana Hendrickson'})-[:KNOWS {relation: 'sister'}]->(b:Person {name: 'Susan Hendrickson'})
RedisGraph would create 2 new nodes and add the relation between them
The generic query for relationship has this form:
(NodeA)-[:Relationship]->(NodeB)
take one minute to appreciate how eloquent and visually clear the syntax of Cypher can be😯👏.
Ok, now we can add some more relationships in the graph:
GRAPH.QUERY Social "MATCH (a:Person {name: 'Susan Hendrickson'}), (b:Person {name: 'Peter Steinmetz'}) CREATE (a)-[:KNOWS {relation: 'married'}]->(b)"
GRAPH.QUERY Social "MATCH (a:Person {name: 'Susan Hendrickson'}), (b:Person {name: 'Louise Rosol'}) CREATE (a)-[:KNOWS {relation: 'friend'}]->(b)"
GRAPH.QUERY Social "MATCH (a:Person {name: 'Peter Steinmetz'}), (b:Person {name: 'Bryce Fett'}) CREATE (a)-[:KNOWS {relation: 'friend'}]->(b)"
GRAPH.QUERY Social "MATCH (a:Person {name: 'Laura Phillips'}), (b:Person {name: 'Louise Rosol'}) CREATE (a)-[:KNOWS {relation: 'coworker'}]->(b)"
GRAPH.QUERY Social "MATCH (a:Person {name: 'Laura Phillips'}), (b:Person {name: 'Diana Hendrickson'}) CREATE (a)-[:KNOWS {relation: 'coworker'}]->(b)"
GRAPH.QUERY Social "MATCH (a:Person {name: 'Louise Rosol'}), (b:Person {name: 'Diana Hendrickson'}) CREATE (a)-[:KNOWS {relation: 'coworker'}]->(b)"
Let's see what we just did:
GRAPH.QUERY Social "MATCH (p:Person) RETURN p"
the graph is exactly the same as before... why?🤔
The reason is that RedisInshight hides relationships by default; if you enable the "All relationship" slide in the upper right side of the graph, RedisInsight will also show you all the relationships between nodes:
Now try to create a connection between an existent node and a non-existent node:
GRAPH.QUERY Social "MATCH (p:Person {name: 'Laura Phillips'}) CREATE (p)-[:KNOWS {relation: 'married'}]->(:Person {name: 'William Stultz', age:33})"
RedisGraph creates for us the unknown node (Person
'William Stultz') and add the relationship between the known node and the new one.
Querying for relationships
Now that we've created some "connections" between nodes, we can query the graph for relation between nodes.
Let's say we want to show every married Person
:
GRAPH.QUERY Social "MATCH (p:Person)-[:KNOWS {relation:'married'}]->(o:Person) RETURN p,o"
Or we need the list of every Person
that knows 'Susan Hendrickson':
GRAPH.QUERY Social "MATCH (p:Person)-[:KNOWS]-(:Person {name: 'Susan Hendrickson'}) RETURN p"
here we made some subtle but important changes to the query: first of all, we don't need the Person
'Susan Hendrickson' so we haven't added an alias to it.
Second: in RedisGraph every relation has a direction (starting from Node A ending on Node B). There's no point in giving the :KNOWS
relation a direction in the last query (two friends are friends to each other, it's a bi-directional relationship).
So we query for the relation without specifying the direction; the syntax (a)-[:KNOWS]->(b)
became (a)-[:KNOWS]-(b)
.
What if instead of the list of acquaintances of 'Susan Hendrickson' we want just the count?
We can use the COUNT
aggregation:
GRAPH.QUERY Social "MATCH (p:Person)-[:KNOWS]-(:Person {name: 'Susan Hendrickson'}) RETURN count(p)"
There is no graph to see here, so RedisGraph only shows the textual output of the COUNT
:
Delete nodes and edges
The last query we'll look at today is the DELETE
:
GRAPH.QUERY Social "MATCH (p:Person {name: 'William Stultz'}) DELETE p"
again, we first MATCH
the node, then we DELETE
it.
As you may remember, we created a relationship between this node and another Person
('Laura Phillips'). When we delete a node, all its relationships are deleted too. This may seems obvious, but it's something to keep in mind.
RECAP
In this post we learned the basics of Cypher and how to query RedisGraph. The topic is vast, we haveve covered a small part of it just to get you started.
In the next (and last) post, I'll show you a more practical example of RedisGraph in action.
Top comments (0)