INTRODUCTION
This blog post is intended to introduce the readers to Graph databases and Open-Cypher graph query language. It takes example of an imaginary Indian restaurant menu, and the tutorial revolves around it.
The reader is expected to have set-up some kind of graph database management system before starting out with this tutorial.
Apache-AGE setup on PostgreSQL has been used to implement Graph database throughout this tutorial.
Read about Apache-AGE here: https://age.apache.org/
GitHub here: https://github.com/apache/age
THE PROBLEM
Suppose that you and I together start an Indian restaurant in Budapest with a modest investment. You are in-charge of management of the restaurant and I am in-charge of food and cooking.
Given our initial investment, we come up with a small and suiting menu for our little cozy restaurant. We go with 1 starter, 4 main curries, 2 types of breads, 1 beverage, and 1 dessert.
We decide to store our menu in the form of a graph database.
How can we achieve it?
Creating nodes
Well, for starters we can store each food item as a node in our Graph database. We can use the label to identify whether it is a starter, curry, beverage, bread or dessert. We can also store some additional properties along with the item such as: -
- name: Name of the food item.
- type: Whether the food is vegan, vegetarian, or non vegetarian.
- price: Price of the food item.
How do we create a node in Open Cypher?
We can create a node in Open Cypher by using the following query syntax: -
CREATE (:LABEL {property1: "VALUE1", property2: "VALUE2"})
To do it in Apache AGE, first create a graph: -
SELECT * FROM ag_catalog.create_graph('menu');
In Apache AGE, the Open Cypher query is inputted like this: -
SELECT * FROM cypher('graph_name', $$
/* Cypher Query Here */
$$) AS (result1 agtype, result2 agtype);
Hence, if we wish to add a node for Samosa in our graph named 'menu', it will look like this: -
SELECT * FROM cypher('menu', $$
CREATE (:STARTER {name: "Samosa", type: "Vegan", price: 30})
$$) AS (result agtype);
Different food items can have different labels and properties. You can experiment with them on your own. For the sake of this tutorial, I have prepared a query to add all the menu items with suitable description to our graph. The query can be found here (along with all other queries used throughout this tutorial).
Query for all nodes
We can confirm that our food items were correctly added by executing a MATCH
query in Open Cypher.
MATCH (n) RETURN n
MATCH
is used to select nodes in Open Cypher. n
is a variable name we have given here. We have not specified any filters so by default all the nodes are selected under variable n
. Return n
outputs those nodes, hence all the nodes are outputted.
Creating relationships
Since we have opened our restaurant in a foreign city, our guests might not be aware of what is supposed to be order with what, or what goes with what. To aid their confusion, we can add relationship 'GOES_WITH' in between food items that are generally ordered with one another. For example: -
- Chai goes well with Samosa.
- Any bread goes well with any curry.
- Rice goes well with Dal or other lentils.
To create relationships between nodes, we will first query for them using MATCH
clause, and then use CREATE
to create a relationship.
The general syntax of querying for items satisfying a certain label and/or properties using MATCH
clause is as follows: -
MATCH (variable_name:label {property_name1: "value1", property_name2: "value2"...})
RETURN variable_name
It is important to note that only those details around which we seek to filter nodes are to be provided.
To create a relationship between 2 nodes, CREATE
clause can be inserted between MATCH
clause and RETURN
clause: -
MATCH (variable_name1:label1 {property_name1: "value1"}), (variable_name2:label2 {property_name2: "value2"})
CREATE (variable_name1)-[:relationship_name {relationship_property:"value"}]->(variable_name2)
RETURN variable_name1, variable_name2
To create a relationship named 'GOES_WITH' in between Chai and Samosa, the following Open Cypher query can be executed: -
MATCH (samosa:STARTER {name: "Samosa"}), (chai:BEVERAGE {name: "Chai"})
CREATE (samosa)-[:GOES_WITH]->(chai)
RETURN samosa, chai
Now, let us create a GOES_WITH relationship between all BREADs and all CURRYs. To do so, we may use the following query: -
MATCH (bread:BREAD), (curry:CURRY)
CREATE (bread)-[:GOES_WITH]->(curry)
RETURN bread, curry
What does rice go with? Rice goes with Dal. We can create a GOES_WITH relationship between rice and dal using the following query: -
MATCH (rice:RICE), (dal:CURRY {name: "Dal Makhani"})
CREATE (rice)-[:GOES_WITH]->(dal)
RETURN rice, dal
Updating nodes
Snap! We just realized that we may have made an error. Given that Dal Makhani has butter in it, it is incorrectly marked as vegan in its properties. We need to update its 'type' property to 'vegetarian' from vegan.
To update property of a node, first we need to select the node in a variable using MATCH
clause, then update its property using SET
clause. The usage has been demonstrated by the following query: -
MATCH (dal:CURRY {name: "Dal Makhani"})
SET dal.type = "Vegetarian"
RETURN dal
Deleting nodes
Let's say in our further discussions, since almost all our food is vegetarian anyway, we can go for a completely vegetarian restaurant. For that, we'd be needed to delete all the 'Non Vegetarian' food items from our menu.
Again, to delete a node, first select it using MATCH
clause, then we can delete it using DELETE
clause. In case the node is part of some relationship, we will be required to DETACH
it first from its existing relationships. So, a query to delete all the nodes of the type 'Non Vegetarian' would look something this: -
MATCH (nv {type:"Non Vegetarian"})
DETACH DELETE nv
RETURN nv
Querying data
Finally, we think our menu is prepared and solid.
Let's test our database out against some typical kinds of customers:
- The Vegans.
Lets try to output all Vegan food items on the menu using
MATCH
clause.
MATCH (v {type: "Vegan"})
RETURN v
- Customer who wants to eat Naan but does not know what to eat it with
MATCH (n:BREAD {name: "Butter Naan"})-[GOES_WITH]-(f)
RETURN f
- Customer who wants a Vegan Curry
MATCH (vc:CURRY {type: "Vegan"})
RETURN vc
Thank you!
Our restaurant is a great success!
All the Apache AGE queries used throughout the post are available here.
Top comments (0)