First we import some simple data, containing nodes and relations into neo4j
neo4j-sh (?)$ CREATE (Client1:client {name:’Ants Konn’, age:34, sex:’M’})
> CREATE (Client2:client {name:’Ivan Orav’, age:66, sex:’M’})
> CREATE (Client3:client {name:’Kadri Kala’, age:24, sex:’F’})
> CREATE (Client4:client {name:’Jaanika Tamm’, age:55, sex:’F’})
>
> CREATE (Basket1:pasket {name:’Basket1′})
> CREATE (Basket2:pasket {name:’Basket2′})
> CREATE (Basket3:pasket {name:’Basket3′})
> CREATE (Basket4:pasket {name:’Basket4′})
> CREATE (Basket5:pasket {name:’Basket5′})
>
> CREATE (Item1:item {name:’Item1′, price:”34″, amount:2})
> CREATE (Item2:item {name:’Item2′, price:”3″, amount:1})
> CREATE (Item3:item {name:’Item3′, price:”4″, amount:3})
> CREATE (Item4:item {name:’Item4′, price:”64″, amount:5})
> CREATE (Item5:item {name:’Item5′, price:”88″, amount:2})
> CREATE (Item6:item {name:’Item6′, price:”32″, amount:1})
> CREATE (Item7:item {name:’Item7′, price:”74″, amount:20})
> CREATE (Item8:item {name:’Item8′, price:”1″, amount:2})
>
> CREATE (Client1)-[:OWN]->(Basket1)
> CREATE (Client1)-[:OWN]->(Basket2)
> CREATE (Client2)-[:OWN]->(Basket3)
> CREATE (Client3)-[:OWN]->(Basket4)
> CREATE (Client4)-[:OWN]->(Basket5)
>
> CREATE (Item1)-[:IN]->(Basket1)
> CREATE (Item2)-[:IN]->(Basket1)
> CREATE (Item3)-[:IN]->(Basket2)
> CREATE (Item4)-[:IN]->(Basket3)
> CREATE (Item5)-[:IN]->(Basket4)
> CREATE (Item6)-[:IN]->(Basket5)
> CREATE (Item7)-[:IN]->(Basket1)
> CREATE (Item7)-[:IN]->(Basket2)
> CREATE (Item7)-[:IN]->(Basket3)
> CREATE (Item7)-[:IN]->(Basket4)
> CREATE (Item7)-[:IN]->(Basket5)
> CREATE (Item8)-[:IN]->(Basket2)
> CREATE (Item8)-[:IN]->(Basket3)
> ;
Now you can visualize your data in different environments.
The easiest way is to use neo4j databrowser
or you can choose some 3th part application to play with your data. In example I use neoclipse
Now we have nodes and relations in db and we can visualize them.
Neo4j is more than tool for data visualization. It is database so we can make queries.
Why do we need queries if we have so nice graphical presentation. In case if we have huge amount of data the graphical presentation may be a little bit difficult to follow and patterns we are looking for my be not so easily found.
Lets see what interesting queries we can produce based on our existing data.
Lets take Item2 (NodeID: 10)
The easiest way to make queries for me is to use neo4j-shell.
Lets pretend we need to know who are buyers of current Item
neo4j-sh (Item2,10)$ MATCH (i {name:’Item2′})-[:IN]-b-[:OWN]-c RETURN i, b, c;
+—————————————————————————————————————-+
| i | b | c |
+—————————————————————————————————————-+
| Node[10]{name:”Item2″,price:”3″,amount:1} | Node[4]{name:”Basket1″} | Node[0]{name:”Ants Konn”,age:34,sex:”M”} |
+—————————————————————————————————————-+
1 row
We can see that Item2 is not very popular product. What about Item7?
neo4j-sh (?)$ MATCH (i {name:’Item7′})-[:IN]-b-[:OWN]-c RETURN i, b, c;
+———————————————————————————————————————+
| i | b | c |
+———————————————————————————————————————+
| Node[15]{name:”Item7″,price:”74″,amount:20} | Node[4]{name:”Basket1″} | Node[0]{name:”Ants Konn”,age:34,sex:”M”} |
| Node[15]{name:”Item7″,price:”74″,amount:20} | Node[5]{name:”Basket2″} | Node[0]{name:”Ants Konn”,age:34,sex:”M”} |
| Node[15]{name:”Item7″,price:”74″,amount:20} | Node[6]{name:”Basket3″} | Node[1]{name:”Ivan Orav”,age:66,sex:”M”} |
| Node[15]{name:”Item7″,price:”74″,amount:20} | Node[7]{name:”Basket4″} | Node[2]{name:”Kadri Kala”,age:24,sex:”F”} |
| Node[15]{name:”Item7″,price:”74″,amount:20} | Node[8]{name:”Basket5″} | Node[3]{name:”Jaanika Tamm”,age:55,sex:”F”} |
+———————————————————————————————————————+
5 rows
24 ms
We can see that Item7 is much popular product comparing with Item2.
So who are buyers bought Item7
neo4j-sh (?)$ MATCH (i {name:’Item7′})-[:IN]-b-[:OWN]-c RETURN DISTINCT c;
+———————————————+
| c |
+———————————————+
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} |
| Node[1]{name:”Ivan Orav”,age:66,sex:”M”} |
| Node[2]{name:”Kadri Kala”,age:24,sex:”F”} |
| Node[3]{name:”Jaanika Tamm”,age:55,sex:”F”} |
+———————————————+
4 rows
37 ms
So very cool queries 🙂
Lets make thinks more interesting and create new relation between customers Ants Konn and Jaanika Tamm and pretend they are couple. Ignore lastnames 🙂
Now we can ask a question in example are there items bought by related persons?
neo4j-sh (?)$ MATCH i-[:IN]-b-[:OWN]-c-[]-c2-[OWN]-b2-[IN]-i RETURN DISTINCT c, i;
+——————————————————————————————-+
| c | i |
+——————————————————————————————-+
| Node[3]{name:”Jaanika Tamm”,age:55,sex:”F”} | Node[15]{name:”Item7″,price:”74″,amount:20} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[15]{name:”Item7″,price:”74″,amount:20} |
+——————————————————————————————-+
2 rows
29 ms
We found that Item7 is the only Item bought by that couple.
Lets make thinks more complicated and add one more relation between Ants Konn and Ivan Orav as father and son. Don’t lool surnames again 🙂 and put Item1 into basket3 as well.
Lets query now Items bought by related customers
neo4j-sh (?)$ MATCH i-[:IN]-b-[:OWN]-c-[]-c2-[OWN]-b2-[IN]-i RETURN DISTINCT c.name, i.name ORDER BY i.name;
+————————–+
| c.name | i.name |
+————————–+
| “Ivan Orav” | “Item1” |
| “Ants Konn” | “Item1” |
| “Jaanika Tamm” | “Item7” |
| “Ivan Orav” | “Item7” |
| “Ants Konn” | “Item7” |
| “Ivan Orav” | “Item8” |
| “Ants Konn” | “Item8” |
+————————–+
7 rows
100 ms
neo4j-sh (?)$
One example about query “my friends friends” that gives as all nodes after node we are connected
neo4j-sh (Ants Konn,0)$ start n=node:node_auto_index(name=’Ants Konn’) MATCH n–()–t RETURN n, t;
+—————————————————————————————-+
| n | t |
+—————————————————————————————-+
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[16]{name:”Item8″,price:”1″,amount:2} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[15]{name:”Item7″,price:”74″,amount:20} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[11]{name:”Item3″,price:”4″,amount:3} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[15]{name:”Item7″,price:”74″,amount:20} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[10]{name:”Item2″,price:”3″,amount:1} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[9]{name:”Item1″,price:”34″,amount:2} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[8]{name:”Basket5″} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[6]{name:”Basket3″} |
+—————————————————————————————-+
8 rows
17 ms
and here we can add information about node we jumped over
neo4j-sh (Ants Konn,0)$ start n=node:node_auto_index(name=’Ants Konn’) MATCH n–(i)–t RETURN n, i, t;
+————————————————————————————————————————————–+
| n | i | t |
+————————————————————————————————————————————–+
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[5]{name:”Basket2″} | Node[16]{name:”Item8″,price:”1″,amount:2} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[5]{name:”Basket2″} | Node[15]{name:”Item7″,price:”74″,amount:20} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[5]{name:”Basket2″} | Node[11]{name:”Item3″,price:”4″,amount:3} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[4]{name:”Basket1″} | Node[15]{name:”Item7″,price:”74″,amount:20} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[4]{name:”Basket1″} | Node[10]{name:”Item2″,price:”3″,amount:1} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[4]{name:”Basket1″} | Node[9]{name:”Item1″,price:”34″,amount:2} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[3]{name:”Jaanika Tamm”,age:55,sex:”F”} | Node[8]{name:”Basket5″} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | Node[1]{name:”Ivan Orav”,age:66,sex:”M”} | Node[6]{name:”Basket3″} |
+————————————————————————————————————————————–+
8 rows
16 ms
neo4j-sh (Ants Konn,0)$
Another query to get relations. So lets get all relations related with Ants Konn
neo4j-sh (Ants Konn,0)$ start n=node:node_auto_index(name=’Ants Konn’) MATCH n-[r]-t RETURN n, r;
+———————————————————–+
| n | r |
+———————————————————–+
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | :OWN[1]{} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | :OWN[0]{} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | :HUSBAND[21]{} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | :SON[22]{} |
+———————————————————–+
4 rows
10 ms
neo4j-sh (Ants Konn,0)$
You can specify relation direction using “>” and “<“. Query relations that goes out from Ants Konn
neo4j-sh (Ants Konn,0)$ sto_index(name=’Ants Konn’) MATCH n-[r]->t RETURN n, r;
+———————————————————–+
| n | r |
+———————————————————–+
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | :OWN[1]{} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | :OWN[0]{} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | :HUSBAND[21]{} |
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | :SON[22]{} |
+———————————————————–+
4 rows
6 ms
And query for incoming relations for Ants Konn
neo4j-sh (Ants Konn,0)$ start n=node:node_auto_index(name=’Ants Konn’) MATCH n<-[r]-t RETURN n, r;
+——-+
| n | r |
+——-+
+——-+
0 row
5 ms
So at the moment there are’t any incoming relation. Lets create one and lets query again.
As you see there is now one incoming relation for Ants Konn. Lets query
neo4j-sh (Ants Konn,0)$ start n=node:node_auto_index(name=’Ants Konn’) MATCH n<-[r]-t RETURN n, r;
+———————————————————-+
| n | r |
+———————————————————-+
| Node[0]{name:”Ants Konn”,age:34,sex:”M”} | :FRIEND[24]{} |
+———————————————————-+
1 row
5 ms
neo4j-sh (Ants Konn,0)$
So Ants Konn is not so lonely any more he has one friend 🙂
One more nice picture about our relations using neo4j web tools
Sow that was a light introduction about some possibilities of neo4j.