We already met the Graph Model a few pages ago. Now we have all the basic knowledge needed to work with OrientDB as a GraphDB! This requires the graph edition of OrientDB. Connect to the GratefulDeadConcerts
database for experimentation. It contains the concerts performed by the "Grateful Dead" band.
OrientDB comes with a generic Vertex persistent class called "V" (OGraphVertex in previous releases) and "E" (OGraphEdge in the past) for Edge. You can create a new Vertex with:
orientdb> insert into V set name = 'Jay'
create record with RID #9:0
In effect, the GraphDB model works on top of the underlying Document model, so all the stuff you have learned until now (Records, Relationships, etc.) remains valid. But in order to simplify the management of the graph we've created special commands, so don't use the SQL Insert command anymore to create a new vertex. Instead, use the ad-hoc "create vertex" command:
orientdb> create vertex V set name = 'Jay'
create vertex with RID #9:1
By using graph commands, OrientDB takes care of ensuring that the graph remains always consistent. All the Graph commands are:
Even though you can work with Vertices and Edges, OrientDB provides the possibility to extend the V
and E
classes. The pros of this approach are:
So from now on, we will avoid using plain V
and E
and will always create custom classes. Let's develop an example graph to model a social network based on restaurants:
orientdb> create class Person extends V
orientdb> create class Restaurant extends V
Now that the schema has been created let's populate the graph with some vertices:
orientdb> create vertex Person set name = 'Luca'
create record with RID #11:0
orientdb> create vertex Person set name = 'Bill'
create record with RID #11:1
orientdb> create vertex Person set name = 'Jay'
create record with RID #11:2
orientdb> create vertex Restaurant set name = 'Dante', type = 'Pizza'
create record with RID #12:0
orientdb> create vertex Restaurant set name = 'Charlie', type = 'French'
create record with RID #12:1
Before we connect them using edges, let's go create a new Edge type:
orientdb> create class Eat extends E
This will represent the relationship from Person to Restaurant. The orientation is important when you create an edge because it gives the meaning of the relationship. If we wanted to model the edge in the opposite orientation, from Restaurant to Person, we might call the Edge class "Attendee", or something similar.
Now let's create a connection between person "Luca" and restaurant "Dante":
orientdb> create edge Eat from (select from Person where name = 'Luca') to (select from Restaurant where name = 'Dante')
If you know the RID of vertices you can connect them with a shorter and faster command. Below we will connect "Bill" with the same "Dante" Restaurant and 'Jay' to 'Charlie' Restaurant:
orientdb> create edge Eat from #11:1 to #12:0
orientdb> create edge Eat from #11:2 to #12:1
Now that our small graph has been created let's play with queries. To cross edges we can use special graph functions like:
out()
, to retrieve the adjacent outgoing verticesin()
, to retrieve the adjacent incoming verticesboth()
, to retrieve the adjacent incoming and outgoing verticesTo know all the people who eat in the "Dante" restaurant (RID = #12:0), we can get Dante's record and then traverse the incoming edges to discover the Person records connected:
orientdb> select in() from Restaurant where name = 'Dante'
+-------+----------------+
| @RID | in |
+-------+----------------+
| #-2:1 | [#11:0, #11:1] |
+-------+----------------+
Those are the RIDs of the Person instances connected. In these cases the expand()
special function becomes very useful to transform the collection of vertices in the resultset by expanding it:
orientdb> select expand( in() ) from Restaurant where name = 'Dante'
+-------+-------------+-------------+---------+
| @RID | @CLASS | Name | out_Eat |
+-------+-------------+-------------+---------+
| #11:0 | Person | Luca | #12:0 |
| #11:1 | Person | Bill | #12:0 |
+-------+-------------+-------------+---------+
Much better! Now let's create the new relationship "Friend" to connect people:
orientdb> create class Friend extends E
And connect "Luca" with "Jay":
orientdb> create edge Friend from #11:0 to #11:2
"Friend" relationship is one of these edge types where the orientation is not important: if "Luca" is a friend of "Jay" the opposite is usually true, so the orientation looses importance. To discover Luca's friends, we should use the both()
function:
orientdb> select expand( both('Friend') ) from Person where name = 'Luca'
+-------+-------------+-------------+---------+-----------+
| @RID | @CLASS | Name | out_Eat | in_Friend |
+-------+-------------+-------------+---------+-----------+
| #11:2 | Person | Jay | #12:1 | #11:0 |
+-------+-------------+-------------+---------+-----------+
In this case I've passed the Edge's class "Friend" as argument of the both()
function to cross only the relationships of kind "Friend" (so skip the "Eat" this time). Note also in the result set that the relationship with "Luca" (RID = #11:0) is in the "in_" field.
Now let's make things more complicated. Get all the restaurants where Luca's friends go.
orientdb> select expand( both('Friend').out('Eat') ) from Person where name = 'Luca'
+-------+-------------+-------------+-------------+---------+
| @RID | @CLASS | Name | Type | in_Eat |
+-------+-------------+-------------+-------------+---------+
| #12:1 | Restaurant | Charlie | French | #11:2 |
+-------+-------------+-------------+-------------+---------+
Cool, isn't it?
Starting from OrientDB v1.4.x edges, by default, are managed as lightweight edges: they don't have own identities as record, but are physically stored as links inside vertices. OrientDB automatically uses Lightweight edges only when edges have no properties, otherwise regular edges are used. From the logic point of view, lightweight edges are edges at all the effects, so all the graph functions work correctly. This is to improve performance and reduce the space on disk. But as a consequence, since lightweight edges don't exist as separate records in the database, the following query will not return the lightweight edges:
SELECT FROM E
In most of the cases Edges are used from Vertices, so this doesn't cause any particular problem. In case you need to query Edges directly, even those with no properties, disable lightweight edge feature by executing this command once:
ALTER DATABASE CUSTOM useLightweightEdges=false
This will only take effect for new edges. For more information look at: https://github.com/orientechnologies/orientdb/wiki/Troubleshooting#why-i-cant-see-all-the-edges.
For more information look at Graph API.