Cypher: sintassi e struttura

29 settembre 2017

Come abbiamo detto nell’introduzione, Neo4j supporta come linguaggio dichiarativo ufficiale Cypher, creato dal team di Neo4j allo scopo di interagire con il database in modo molto semplice e con una curva di apprendimento il più possibile bassa per sviluppatori abituati ad usare SQL.

Inoltre, utilizzando il driver JDBC per Neo4j, è possibile sostituire il database in qualsiasi stack JVM che utilizzi JDBC, oppure utilizzarlo con molti strumenti di reportistica.

Per prima cosa, per quanto riguarda etichette, proprietà e relazioni, Cypher è case-sensitive: questo significa che è necessario prestare attenzione alle maiuscole quando si scrivono le query. Se si seguono le convenzioni che segnaleremo in seguito, dovremmo facilmente evitare errori.

In Cypher, un’istruzione si compone generalmente di tre parti, una di interrogazione, opzionalmente uno o più comandi, e un’istruzione di ritorno per indicare eventuali valori da restituire. Come vedremo in seguito, più istruzioni possono essere concatenate e si possono usare valori precedentemente letti dal database. Questo significa che si possono scrivere query come la seguente, in cui abbiamo l’interrogazione, la ricerca di alcuni nodi, a seguire la creazione di una nuova relazione con un nuovo nodo e infine la restituzione dei nodi trovati e creati.

MATCH (u)-[i:ISCRITTO_A]->(:Corso {nome: 'Corso di Neo4j'}) 
WHERE i.scadenza < '2017' 
CREATE (u)-[:LEGGE]->(l:Libro { titolo: 'Neo4j Cookbook' })
RETURN u,l

Andiamo nel dettaglio della query precedente. Con la prima riga abbiamo cercato tutti i nodi che abbiamo collegato alla variabile u, aventi una relazione di tipo ISCRITTO_A che abbiamo collegato alla variabile i, con un qualsiasi nodo avente la proprietà nome uguale al valore “Corso di Neo4j”. In questa prima parte della query vengono selezionate quelle porzioni di grafo che soddisfano il pattern appena specificato (pattern matching). Con la seconda riga abbiamo filtrato i risultati selezionando solo quelli in cui la proprietà scadenza è specificata ed è minore di 2017, come in SQL. Nella terza riga, invece, abbiamo creato, per ogni risultato trovato, una relazione di tipo LEGGE tra il nodo u e un nuovo nodo avente la proprietà titolo uguale al testo “Neo4j Cookbook”. Infine, con <code>RETURN</code> abbiamo indicato di restituire i nodi u e l. Alcune annotazioni:

  1. se la prima istruzione non trova alcun nodo, non ci sarà alcuna creazione e quindi nessuna riga restituita;
  2. per ogni risultato trovato verrà creato un nuovo nodo con etichetta Libro. Più avanti vedremo come che è possibile creare pattern assicurandosi che siano unici.

Il risultato della query è il seguente:

╒═════════════════════════╤════════════════════════╕
│u                        │l                       │
╞═════════════════════════╪════════════════════════╡
│{username: verdi@html.it}│{titolo: Neo4j Cookbook}│
├─────────────────────────┼────────────────────────┤
│{username: rossi@html.it}│{titolo: Neo4j Cookbook}│
└─────────────────────────┴────────────────────────┘

Vediamo appunto che abbiamo nella prima colonna (u) il nodo trovato sul database, mentre nella seconda (l) il nodo creato.

I pattern

Abbiamo visto che per valorizzare alcune variabili che rappresentano ciò che stiamo cercando nel database, dobbiamo specificare una parte di grafo da creare (CREATE) o da far corrispondere (MATCH).

La sintassi usata da Cypher per rappresentare questi pattern è molto semplice. Vediamone alcuni esempi.

Nodi

Tutto ciò che è tra parentesi tonde è un nodo. Detto ciò, è possibile esprimere varie condizioni; ad esempio:

  • () fa match con qualsiasi nodo;
  • (:Libro) corrisponde a qualsiasi nodo con etichetta User. Per convenzione, le etichette hanno la sola iniziale maiuscola;
  • ({ titolo: 'Neo4j Cookbook' , pagine: 210 }) corrisponde a qualsiasi nodo avente le proprietà titolo e pagine entrambe con in valori indicati. Per convenzione generalmente le proprietà sono tutte in minuscolo;
  • il pattern che specifica sia l’etichetta sia le proprietà: (:Libro { titolo: 'Neo4j Cookbook' , pagine: 210 }) corrisponde ai nodi che rispettano tutte le condizioni: sia l’etichetta sia le proprietà valorizzate con i valori indicati;
  • per indicare che vogliamo collegare il valore di una variabile ad ogni nodo che corrisponde al pattern, dobbiamo specificare il nome della variabile subito dopo l’apertura della parentesi: (cookbook:Libro { titolo: 'Neo4j Cookbook' , pagine: 210 }). In questo caso abbiamo dato il nome cookbook ai nodi trovati. Le variabili sono comode successivamente per referenziare gli elementi corrispondenti, come abbiamo visto in precedenza nella clausola WHERE.

Relazioni

Tutto ciò che è tra parentesi quadrate è una relazione, o una catena di relazioni. Ad esempio:

  • -[]- fa match con qualsiasi relazione, e qualsiasi verso;
  • -[]-> fa match con qualsiasi relazione, e verso dal nodo specificato a sinistra a quello di destra. Ovviamente la sintassi <-[]- indica il verso opposto;
  • -[i:ISCRITTO_A] corrisponde a qualsiasi relazione di tipo ISCRITTO_A. Per convenzione le etichette hanno la sola iniziale maiuscola;
  • -[{ scadenza: '2017-11-01'}]-> corrisponde a qualsiasi relazione avente la proprietà scadenza con il valore indicato. Anche qui per convenzione le proprietà sono in minuscolo;
  • il pattern che specifica sia il tipo sia le proprietà corrisponde a relazioni che rispettano tutte le condizioni, come abbiamo visto per i nodi. Per esempio: [:ISCRITTO_A { scadenza: '2017-11-01'}];
  • per indicare che vogliamo collegare il valore di una variabile ad ogni relazione che corrisponde al pattern, anche qui dobbiamo specificare il nome della variabile subito dopo l’apertura della parentesi: -[i:ISCRITTO_A]->;
  • se vogliamo indicare che tra due nodi ci può essere una catena con al massimo 2 relazioni, possiamo usare la sintassi -[*1..2]->. Naturalmente, possiamo combinare il pattern con quelli usati in precedenza e scrivere pattern fatti così: -[:CONOSCE*2..]- per indicare che vogliamo catene di relazioni di tipo CONOSCE con almeno 2 relazioni.

Tutte le lezioni

1 2 3 4 ... 8

Se vuoi aggiornamenti su Cypher: sintassi e struttura inserisci la tua e-mail nel box qui sotto:
Tags: ,
 
X
Se vuoi aggiornamenti su Cypher: sintassi e struttura

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy