Hands on Neo4j
This is the script of a hands on session on MongoDB. The example refers to a typical retail example [ER diagram] with orders [CSV], products [CSV] and users [CSV].
getting a Neo4j running on your machine using docker
docker pull neo4j
docker run -p 7474:7474 -p 7687:7687 -d neo4j
then open http://localhost:7474 and enter the password (neo4j)
let’s see an example where neo4j rocks
Relational data describing a taxonomi
The categories
categrories | |
---|---|
ID | Name |
0 | top |
1 | sub1 |
2 | sub2 |
11 | sub1.1 |
12 | sub1.2 |
121 | sub1.2.1 |
the relationships among the categories
relationships | |
---|---|
src | dest |
0 | 1 |
0 | 2 |
1 | 11 |
1 | 12 |
12 | 121 |
let’s now create this taxonomy in neo4j
syntax
- nodes
CREATE (<variabile>:<tipo> {<field>: <valore>})
and - edges
CREATE (<variabile>)-[:<proriterĂ >]->(<variabile>)
example
CREATE (top:Category {name: "top"})
CREATE (sub1:Category {name: "sub1"})
CREATE (sub2:Category {name: "sub2"})
CREATE (sub11:Category {name: "sub1.1"})
CREATE (sub12:Category {name: "sub1.2"})
CREATE (sub121:Category {name: "sub1.2.1"})
CREATE (top)-[:narrower]->(sub1),
(top)-[:narrower]->(sub2),
(sub1)-[:narrower]->(sub11),
(sub1)-[:narrower]->(sub12),
(sub12)-[:narrower]->(sub121)
let’s query it in cypher
Syntax
MATCH (<variabile>?:<tipo>? {<field>: <valore>}*)
-[<variabile>?:<tipo>? {<field>: <valore>}*]->?
(<variabile>?:<tipo>? {<field>: <valore>}*)?
WHERE <condition>?
RETURN <variabile>+
examples
walking one edge
All the nodes that can be reached from a node named top following one edge of type narrower
SQL
SELECT *
FROM relationships AS R JOIN categories AS C ON R.src = C.ID
WHERE C.name = 'top'
cypher
MATCH p=(a)-[:narrower]->() WHERE a.name="top" RETURN p
NOTE: not such a big difference …
walking down the entire taxonomi
all the nodes that can be reached from a node named top following any number ofedges of type narrower
SQL
SELECT R.dest, R1.dest, R2.dest
FROM relationships AS R JOIN categories AS C ON R.src = C.ID JOIN
relationships AS R1 ON R1.src = R.dest JOIN
relationships AS R2 ON R2.src = R1.dest JOIN
relationships AS R3 ON R3.src = R2.dest
WHERE C.name = 'top'
NOTE: what if the taxonomy was deeper? What if you don’t know how deep the taxonomy is?
cypher
MATCH p=(a)-[:narrower*]->() WHERE a.name="top" RETURN p
NOTE: Wow! This is easy!!! Thank you cypher!
controlling the number of walks
all the nodes that can be reached from a node named top following a minimum of 3 and a maximum of 3 edges of type narrower
MATCH p=(a)-[:narrower*2..3]->() WHERE a.name="top" RETURN p
let’s add some relational data
syntax
importing users
LOAD CSV FROM
'http://emanueledellavalle.org/data/neo4j/retail/users.csv' AS line
CREATE (:User {uid: toInteger(line[0]), name: line[1]})
importing products
LOAD CSV FROM
'http://emanueledellavalle.org/data/neo4j/retail/products.csv' AS line
CREATE (:Product {uid: line[0], brand: line[2], name: line[1]})
importing and merging orders
LOAD CSV FROM
'http://emanueledellavalle.org/data/neo4j/retail/orders.csv' AS line
MATCH (user:User {uid: toInteger(line[1])})
MATCH (product:Product {uid: line[2]})
MERGE (order:Order {id: toInteger(line[0])})
ON CREATE SET order.date = line[4]
MERGE (order)-[:contains {qty: toInteger(3)}]->(product)
MERGE (order)-[:orderedBy]->(user)
NOTE: the MERGE clause ensures that a pattern exists in the graph. Either the pattern already exists, or it needs to be created.
let’s add a category to a product and see neo4j rocking again!
MATCH (category:Category {name: "sub1.2.1"})
MATCH (product:Product {uid: "a"})
MERGE (product)-[:topic]->(category)
MATCH (order)-[:contains]->(product),
(product)-[:topic]->(category),
(supercategory)-[:narrower*]->(category)
WHERE supercategory.name="sub1"
RETURN order, product, category
NOTE: WOW! This is SQL is, in general, impossible to write!
links
- https://neo4j.com/docs/cypher-refcard/current/