La strutturazione dei dati "a grafo" è una delle possibilità più caratteristiche di OrientDB e, più in generale, di molti altri DBMS NoSQL. Seguendo questo approccio, le informazioni vengono strutturate su nodi, detti comunemente vertici, collegati tra loro mediante archi. Utilizzando opportunamente questo genere di elementi, si riesce a creare un sistema di connessioni rappresentanti reti di dati, che possono essere opportunamente esplorati e quindi estratti.
In questa lezione inizieremo ad esplorare come gestire il modello a grafo di OrientDB con i comandi SQL messi a disposizione, sperimentandone l'uso con un esempio pratico.
Grafi, classi e SQL
OrientDB è dotato di due classi che rappresentano i concetti fondamentali di un database a grafo: V per i vertici ed E per gli archi. Inoltre, il linguaggio SQL del DBMS mette a disposizione quattro comandi per la manipolazione di vertici e archi:
- CREATE VERTEX per la creazione di un nodo del grafo fondato su una specifica classe;
- DELETE VERTEX per l'eliminazione di un nodo del grafo;
- CREATE EDGE per stabilire un collegamento tra due nodi, specificando i vertici sorgente e destinazione della connessione;
- DELETE EDGE per la rimozione di un collegamento tra due nodi.
È fondamentale che le classi che devono rappresentare nodi e archi derivino, rispettivamente, da V ed E. Per fare ciò, sfrutteremo il principio dell'ereditarietà, implementato in OrientDB nel modello Object-Oriented. Ad esempio, per fare in modo che la classe B derivi dalla classe A si farà uso della parola chiave extends, analogamente a quanto accade in Java:
CREATE CLASS B extends A
L'esempio: una rete di trasporti
Supponiamo di voler realizzare un grafo che rappresenti le tratte praticate dai pullman di un'azienda di trasporti: i vertici saranno le città mentre gli archi costituiranno i collegamenti disponibili tra le varie località.
Il comando seguente crea una classe Citta come estensione di un generico vertice:
CREATE CLASS Citta extends V
Ora che esiste nel nostro database una classe per definire i nodi del grafo, possiamo istanziarne alcuni:
CREATE VERTEX Citta SET nome='Roma'
CREATE VERTEX Citta SET nome='Milano'
CREATE VERTEX Citta SET nome='Genova'
CREATE VERTEX Citta SET nome='Napoli'
CREATE VERTEX Citta SET nome='Venezia'
CREATE VERTEX Citta SET nome='Ancona'
I vertici così creati rappresentano alcune delle possibili destinazioni raggiungibili tramite i mezzi dell'azienda di trasporto. Essi in realtà non sono altro che record appartenenti ad una classe, ma per la loro natura di vertici OrientDB è preparato a trattarli adeguatamente.
Potremo ottenere i vertici appena inseriti con una semplice query di selezione:
SELECT FROM Citta
Il comando precedente produrrà il seguente output:
# |@RID |@CLASS|nome
----+------+------+-------
0 |#18:11|Citta |Roma
1 |#18:12|Citta |Milano
2 |#18:13|Citta |Genova
3 |#18:14|Citta |Napoli
4 |#18:15|Citta |Venezia
5 |#18:16|Citta |Ancona
----+------+------+-------
Immaginiamo ora che alcune delle tratte previste siano le seguenti:
- da Genova a Milano
- da Milano a Roma
- da Roma a Napoli
- da Milano a Venezia
- da Venezia a Ancona
- da Ancona a Roma
Per la rappresentazione delle tratte, procederemo in maniera analoga a quanto appena fatto. Definiamo una classe che estenda E:
CREATE CLASS Tratta extends E
Stabiliamo i collegamenti:
// da Genova a Milano
CREATE EDGE Tratta FROM #18:13 TO #18:12
// da Milano a Roma
CREATE EDGE Tratta FROM #18:12 TO #18:11
// da Roma a Napoli
CREATE EDGE Tratta FROM #18:11 TO #18:14
// da Milano a Venezia
CREATE EDGE Tratta FROM #18:12 TO #18:15
// da Venezia a Ancona
CREATE EDGE Tratta FROM #18:15 TO #18:16
// da Ancona a Roma
CREATE EDGE Tratta FROM #18:16 TO #18:11
La sintassi del comando CREATE EDGE
è piuttosto intuitiva: tramite le keyword FROM
e TO
vengono specificate la sorgente e la destinazione del collegamento (identificati dai relativi RID). In alternativa, si potrebbe evitare di indicare esplicitamente gli ID tramite una query:
// da Milano a Roma
CREATE EDGE Tratta FROM (SELECT FROM Citta WHERE nome='Milano') TO (SELECT FROM Citta WHERE nome='Roma')
Se provassimo ora ad effettuare una query sulla classe Citta, otterremmo il seguente output:
# |@RID |@CLASS|nome |in_Tratta|out_Tratta
----+------+------+-------+---------+----------
0 |#18:11|Citta |Roma |[size=2] |[size=1]
1 |#18:12|Citta |Milano |[size=1] |[size=2]
2 |#18:13|Citta |Genova |null |[size=1]
3 |#18:14|Citta |Napoli |[size=1] |null
4 |#18:15|Citta |Venezia|[size=1] |[size=1]
5 |#18:16|Citta |Ancona |[size=1] |[size=1]
----+------+------+-------+---------+----------
Come si vede, i record includono ora due nuovi campi: in_tratta che mostra il numero di archi "in" (entranti nel nodo), ed out_tratta che rappresenta il numero di archi "out" (uscenti dal nodo).
Le funzioni in()
e out()
permettono di elencare gli archi entranti e uscenti, mentre both()
li riporta entrambi. Se, ad esempio, volessimo conoscere gli archi con destinazione Roma, la seguente query:
SELECT in() FROM Citta WHERE nome='Roma'
restituirebbe il seguente output:
# |@CLASS|in
----+------+----
0 |null |[2]
----+------+----
dove il campo in indica il numero di archi entranti. Per sapere i dettagli degli archi in ingresso possiamo far uso della funzione expand()
:
SELECT expand(in()) FROM Citta WHERE nome='Roma'
il cui output chiarirà che le tratte disponibili per arrivare a Roma partono da Milano ed Ancona:
# |@RID |@CLASS|nome |out_Tratta|in_Tratta
----+------+------+------+----------+---------
0 |#18:12|Citta |Milano|[size=2] |[size=1]
1 |#18:16|Citta |Ancona|[size=1] |[size=1]
----+------+------+------+----------+---------
Cancellare archi e nodi
Vertici e archi possono anche essere cancellati e per farlo, come detto precedentemente, si può ricorrere a due appositi comandi: DELETE VERTEX
e DELETE EDGE
. Le modalità di utilizzo sono varie. Innanzitutto, si può cancellare un vertice selezionandolo sulla base del suo ID:
DELETE VERTEX #11:5
In tal caso non è necessario indicare la classe di appartenenza visto che l'ID è univoco per i record dell'intero database.
In alternativa, si può utilizzare l'indicazione della classe ed una clausola WHERE
per selezionare i vertici da eliminare:
DELETE VERTEX Citta WHERE nome='Genova'
Anche per gli archi si usano comandi simili. Si può ricorrere ad un intervallo di ID:
DELETE EDGE FROM #12:2 TO #12:5
al quale si può eventualmente collegare una clausola WHERE
per filtrare ulteriormente gli archi da eliminare. Si possono anche sfruttare i campi della classe, nel caso ciò fosse necessario:
DELETE EDGE Corsi WHERE inizio < "2015-09"