Una guida a Neo4J con Java

1. Introduzione

Questo articolo riguarda Neo4j , uno dei database di grafici più maturi e completi oggi sul mercato. I database a grafo affrontano il compito della modellazione dei dati con la visione che molte cose nella vita si prestano ad essere rappresentate come una raccolta di nodi (V) e connessioni tra loro chiamate bordi (E).

2. Neo4j incorporato

Il modo più semplice per iniziare con Neo4j è utilizzare la versione incorporata in cui Neo4j viene eseguito nella stessa JVM dell'applicazione.

Innanzitutto, dobbiamo aggiungere una dipendenza Maven:

 org.neo4j neo4j 3.4.6 

Puoi controllare questo link per scaricare l'ultima versione.

Quindi, creiamo una fabbrica:

GraphDatabaseFactory graphDbFactory = new GraphDatabaseFactory();

Infine, creiamo un database incorporato:

GraphDatabaseService graphDb = graphDbFactory.newEmbeddedDatabase( new File("data/cars"));

Ora può iniziare la vera azione! Innanzitutto, dobbiamo creare alcuni nodi nel nostro grafico e per questo, dobbiamo avviare una transazione poiché Neo4j rifiuterà qualsiasi operazione distruttiva a meno che non sia stata avviata una transazione:

graphDb.beginTx();

Una volta che abbiamo una transazione in corso, possiamo iniziare ad aggiungere nodi:

Node car = graphDb.createNode(Label.label("Car")); car.setProperty("make", "tesla"); car.setProperty("model", "model3"); Node owner = graphDb.createNode(Label.label("Person")); owner.setProperty("firstName", "baeldung"); owner.setProperty("lastName", "baeldung");

Qui abbiamo aggiunto un nodo Auto con le proprietà marca e modello , nonché il nodo Persona con proprietà firstName e lastName

Ora possiamo aggiungere una relazione:

owner.createRelationshipTo(car, RelationshipType.withName("owner"));

La dichiarazione precedente ha aggiunto un bordo che unisce i due nodi con un'etichetta del proprietario . Possiamo verificare questa relazione eseguendo una query scritta nel potente linguaggio Cypher di Neo4j :

Result result = graphDb.execute( "MATCH (c:Car) <-[owner]- (p:Person) " + "WHERE c.make = 'tesla'" + "RETURN p.firstName, p.lastName");

Qui chiediamo di trovare un proprietario di auto per qualsiasi auto la cui marca sia tesla e di restituirci il suo nome e cognome. Non sorprende che questo restituisca: {p.firstName = baeldung, p.lastName = baeldung}

3. Cypher Query Language

Neo4j fornisce un linguaggio di query molto potente e abbastanza intuitivo che supporta l'intera gamma di funzionalità che ci si aspetterebbe da un database. Esaminiamo come possiamo realizzare quelle attività standard di creazione, recupero, aggiornamento ed eliminazione.

3.1. Crea Node

La parola chiave Create può essere utilizzata per creare sia nodi che relazioni.

CREATE (self:Company {name:"Baeldung"}) RETURN self

Qui abbiamo creato un'azienda con un unico nome di proprietà . Una definizione di nodo è contrassegnata da parentesi e le sue proprietà sono racchiuse tra parentesi graffe. In questo caso, self è un alias per il nodo e Company è un'etichetta del nodo.

3.2. Crea relazione

È possibile creare un nodo e una relazione con quel nodo tutto in una singola query:

Result result = graphDb.execute( "CREATE (baeldung:Company {name:\"Baeldung\"}) " + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + "RETURN baeldung, tesla");

Qui abbiamo creato i nodi baeldung e tesla e stabilito una relazione di proprietà tra di loro. Ovviamente è anche possibile creare relazioni con nodi preesistenti.

3.3. Recupera dati

La parola chiave MATCH viene utilizzata per trovare i dati in combinazione con RETURN per controllare quali punti dati vengono restituiti. La clausola WHERE può essere utilizzata per filtrare solo quei nodi che hanno le proprietà che desideriamo.

Cerchiamo di capire il nome della società che possiede Tesla ModelX:

Result result = graphDb.execute( "MATCH (company:Company)-[:owns]-> (car:Car)" + "WHERE car.make='tesla' and car.model='modelX'" + "RETURN company.name");

3.4. Aggiorna nodi

La parola chiave SET può essere utilizzata per aggiornare le proprietà o le etichette dei nodi. Aggiungiamo il chilometraggio alla nostra tesla:

Result result = graphDb.execute("MATCH (car:Car)" + "WHERE car.make='tesla'" + " SET car.milage=120" + " SET car :Car:Electro" + " SET car.model=NULL" + " RETURN car");

Qui aggiungiamo una nuova proprietà chiamata milage , modifichiamo le etichette in modo che siano sia Car che Electro e, infine, eliminiamo completamente la proprietà del modello .

3.5. Elimina nodi

La parola chiave DELETE può essere utilizzata per la rimozione permanente di nodi o relazioni dal grafico:

graphDb.execute("MATCH (company:Company)" + " WHERE company.name='Baeldung'" + " DELETE company");

Qui abbiamo cancellato una società chiamata Baeldung.

3.6. Associazione dei parametri

Negli esempi precedenti, abbiamo valori dei parametri hard-coded che non sono la best practice. Fortunatamente, Neo4j fornisce una funzione per associare variabili a una query:

Map params = new HashMap(); params.put("name", "baeldung"); params.put("make", "tesla"); params.put("model", "modelS"); Result result = graphDb.execute("CREATE (baeldung:Company {name:$name}) " + "-[:owns]-> (tesla:Car {make: $make, model: $model})" + "RETURN baeldung, tesla", params);

4. Driver Java

Finora abbiamo cercato di interagire con un'istanza Neo4j incorporata , tuttavia, con ogni probabilità per la produzione, vorremmo eseguire un server autonomo e connettersi ad esso tramite un driver fornito. Per prima cosa, dobbiamo aggiungere un'altra dipendenza nel nostro maven pom.xml :

 org.neo4j.driver neo4j-java-driver 1.6.2 

È possibile seguire questo collegamento per verificare la versione più recente di questo driver.

Ora possiamo stabilire una connessione:

Driver driver = GraphDatabase.driver( "bolt://localhost:7687", AuthTokens.basic("neo4j", "12345"));

Quindi, crea una sessione:

Session session = driver.session();

Infine, possiamo eseguire alcune query:

session.run("CREATE (baeldung:Company {name:\"Baeldung\"}) " + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + "RETURN baeldung, tesla");

Una volta terminato tutto il nostro lavoro, dobbiamo chiudere sia la sessione che il driver:

session.close(); driver.close();

5. Driver JDBC

It is also possible to interact with Neo4j via a JDBC driver. Yet another dependency for our pom.xml:

 org.neo4j neo4j-jdbc-driver 3.4.0 

You can follow this link to download the latest version of this driver.

Next, let's establish a JDBC connection:

Connection con = DriverManager.getConnection( "jdbc:neo4j:bolt://localhost/?user=neo4j,password=12345,scheme=basic");

Here con is a regular JDBC connection which can be used for creating and executing statements or prepared statements:

try (Statement stmt = con. stmt.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + "RETURN baeldung, tesla") ResultSet rs = stmt.executeQuery( "MATCH (company:Company)-[:owns]-> (car:Car)" + "WHERE car.make='tesla' and car.model='modelX'" + "RETURN company.name"); while (rs.next()) { rs.getString("company.name"); } }

6. Object-Graph-Mapping

Object-Graph-Mapping or OGM is a technique which enables us to use our domain POJOs as entities in the Neo4j database. Let us examine how this works. The first step, as usually, we add new dependencies to our pom.xml:

 org.neo4j neo4j-ogm-core 3.1.2   org.neo4j neo4j-ogm-embedded-driver 3.1.2 

You can check the OGM Core Link and OGM Embedded Driver Link to check for the latest versions of these libraries.

Second, we annotate our POJO's with OGM annotations:

@NodeEntity public class Company { private Long id; private String name; @Relationship(type="owns") private Car car; } @NodeEntity public class Car { private Long id; private String make; @Relationship(direction = "INCOMING") private Company company; }

@NodeEntity informs Neo4j that this object will need to be represented by a node in the resulting graph. @Relationship communicates the need to create a relationship with a node representing the related type. In this case, a company owns a car.

Please note that Neo4j requires each entity to have a primary key, with a field named id being picked up by default. An alternatively named field could be used by annotating it with @Id @GeneratedValue.

Then, we need to create a configuration that will be used to bootstrap Neo4j‘s OGM. For simplicity, let us use an embedded in-memory only database:

Configuration conf = new Configuration.Builder().build();

After that, we initialize SessionFactory with the configuration we created and a package name in which our annotated POJO's reside:

SessionFactory factory = new SessionFactory(conf, "com.baeldung.graph");

Finally, we can create a Session and begin using it:

Session session = factory.openSession(); Car tesla = new Car("tesla", "modelS"); Company baeldung = new Company("baeldung"); baeldung.setCar(tesla); session.save(baeldung);

Here we initiated a session, created our POJO's and asked OGM session to persist them. Neo4j OGM runtime transparently converted objects to a set of Cypher queries which created appropriate nodes and edges in the database.

If this process seems familiar, that is because it is! That is precisely how JPA works, the only difference being whether object gets translated into rows that are persisted to an RDBMS, or a series of nodes and edges persisted to a graph database.

7. Conclusion

Questo articolo ha esaminato alcune basi di un database orientato ai grafici Neo4j.

Come sempre, il codice in questo articolo è tutto disponibile su Github.