Schreiben von Anfragen an Neo4j / Sudo Null IT News

Dies ist der zweite Artikel über die Graphdatenbank Neo4j. Den ersten Artikel über Datenschemamodellierung können Sie hier lesen: https://habr.com/en/post/677296/

Die Essenz des Artikels ist ein kleiner praktischer Exkurs, bevor wir die neuen Konzepte in Neo4j analysieren.

Alle im Artikel angegebenen Beispiele funktionieren, wenn Sie sie herunterladen und installieren Verknüpfung lokal kostenlose Kopie von Neo4j mit vorinstalliertem Movie DBMS.

Anfragen schreiben

Analysieren wir die einfachste Syntax zum Schreiben von Abfragen an Neo4j mit CRUD.

Lesen von Daten

Zuerst müssen wir uns daran erinnern, dass wir in der Datenstruktur Folgendes haben:

  • Knoten – Entitäten;

  • Labels – Labels für Entitäten;

  • Beziehungen – Einwegbeziehungen zwischen Entitäten;

  • Eigenschaften – Eigenschaften von Entitäten oder Beziehungen.

Sehr vereinfacht kann das grundlegende Abfragemuster zum Lesen von Datensätzen wie folgt beschrieben werden:

(: [{<property>: <value>[, …]}])[:<relationship>](:[{<property>: <value>[, …]}])

Ich stimme zu, mit einem Beispiel wird es klarer 🙂

Rufen wir unsere Datenbank mit Filmen und Schauspielern auf und versuchen, sie abzufragen

// Finde alle Filme MATCH (m:Movie) RETURN m

Um eine Auswahl zu erhalten, wird das Schlüsselwort MATCH verwendet (eine exakte Kopie von SELECT aus RDBMS).

m:Movie – hier weisen wir der Variable m alle gefundenen Filme gemäß den gegebenen Bedingungen zu.

RETURN p – explizit angeben was sollte unsere Anfrage zurückgeben.

Mehr Beispiele:

// Finde alle Schauspieler namens Tom Hanks: MATCH (p:Person {name: ‘Tom Hanks’}) RETURN p

{name: ‘Tom Hanks’} — Filterbedingung für die Person-Entität

Aber eine Graphdatenbank wäre keine solche, wenn sie nicht das Hauptmerkmal hätte: Beziehungen zwischen Entitäten.

Lassen Sie uns alle Filme finden, in denen Tom Hanks mitgespielt hat:

MATCH (p:Person {Name: ‘Tom Hanks’})–>(m) RETURN m.title

m – Hier weisen wir der Variablen m alle abhängigen Entitäten zu, die gemäß den angegebenen Bedingungen gefunden wurden.

Exzellent! Aber falsch 🙂 Weil dies uns alle seine Beziehungen mit allen abhängigen Entitäten in der gesamten Datenbank zurückgibt, falls vorhanden. Wir brauchen es nicht, wir wollen die Filme bekommen, in denen er mitgespielt hat. Fügen wir den Verbindungstyp ACTED_IN hinzu:

MATCH (p:Person {Name: ‘Tom Hanks’})-[:ACTED_IN]->(m) RETURN m.Titel

Schon besser, aber auch ungenau. Diese Abfrage wird zurückgegeben alle Unternehmen, in denen er spielte, nicht nur Filme. Er könnte auch in Theaterproduktionen mitspielen, oder?

Diese obigen Beispiele funktionieren dank der sogenannten Fähigkeit Traversein Bezug auf Neo4j.

Ein Knoten, der zumindest irgendwie mit einem anderen Knoten verbunden ist (sogar über andere N Knoten), – befahrbar-aber ja.

Insbesondere gibt es in unserem Datenschema keine anderen Entitäten, sodass wir nur Filme erhalten. Aber es ist besser, keine technischen Schulden anzuhäufen, sondern ausdrücklich darauf hinzuweisen, dass wir nur Filme erwarten:

MATCH (p:Person {Name: ‘Tom Hanks’})-[:ACTED_IN]->(m:Movie) RETURN m.Titel

Jetzt super!

Mehr Beispiele:

// Finden Sie eine Liste aller Schauspieler aus “The Matrix” MATCH (m:Movie {title: ‘The Matrix’})<-[:ACTED_IN]-(p:Person) RETURN p // Finden Sie alle Direktoren, die vor 1970 geboren wurden // Hinweis: Uns ist egal, WAS genau sie geleitet haben, // also geben wir den Knotentyp nicht an: MATCH (p:Person)-[:DIRECTED]->() WHERE p.geb. < 1970 RETURN p

Verbindungen können kombiniert werden:

// Finde alle Filme, in denen Tom Hanks sowohl Schauspieler als auch Regisseur war: MATCH (m:Movie)<-[:ACTED_IN|:DIRECTED]-(p:Person {Name: 'Tom Hanks'}) RETURN m.Titel, p.Name

Im Allgemeinen funktioniert das Schlüsselwort WHERE fast genauso wie in RDBMS, daher werde ich nicht näher darauf eingehen. Es gibt jedoch interessante Anwendungen im Rahmen des Link-Checks:

// Alle Schauspieler finden, die in den Filmen mitgespielt haben, // aber nicht Regie geführt haben: MATCH (p:Person)-[:ACTED_IN]->(m:Movie) WO NICHT existiert( (p)-[:DIRECTED]->(m) ) RETURN p.name, m.title // Greife auf das Link-Attribut zu: // finde den Namen des Schauspielers, der Neo im Matrix MATCH gespielt hat (p:Person)-[r:ACTED_IN]->(m:Movie) WO ‘Neo’ IN r.roles UND m.title=”The Matrix” RETURN p.name, r.roles

Datenaufzeichnung

Um Daten zu Neo4j hinzuzufügen, wird das Wort MERGE verwendet, aber es wäre ein großer Fehler, eine vollständige Analogie mit den Schlüsselwörtern CREATE oder INSERT von RDBMS zu ziehen.

Der Punkt ist, dass MERGE erstellt Muster in der Datenbank.

Einfacher geht es mit Beispielen:

// Einen Personenknoten namens Michael Cain erstellen MERGE (p:Person {name: ‘Michael Cain’}) // Zwei Knoten erstellen (ja, das ist eine Anfrage für drei Zeilen) MERGE (p:Person {name: ‘Katie Holmes’ }) MERGE (m:Movie {title: ‘The Dark Knight’}) RETURN p, m

Kleiner Exkurs: Sie können auch das Schlüsselwort CREATE verwenden, mit dem einzigen Unterschied, dass CREATE nicht anhand des Primärschlüssels prüft, ob ein solcher Knoten bereits in der Datenbank existiert – das bringt einen enormen Geschwindigkeitsvorteil. CREATE wird am häufigsten für Dumps verwendet, damit sie schnell auf einer sauberen Basis bereitgestellt werden können. MERGE fügt Daten genauer ein – mit allen geprüften Bedingungen, aber auch langsamer.

Lassen Sie uns ein einfaches Muster mit MERGE erstellen:

MATCH (p: Person {name: ‘Michael Cain’}) MATCH (m: Movie {title: ‘The Dark Knight’}) MERGE (p)-[:ACTED_IN]->(m)

Nichts hat sich verändert.

Tatsache ist, dass MATCH uns in dieser Abfrage mitteilt, dass wir Datensätze finden sollen, und MERGE, dass wir eine Beziehung zwischen ihnen herstellen sollen. Wenn jedoch keine Datensätze gefunden werden, wird die Verknüpfung nicht erstellt. Um sicherzustellen, dass eine Entität oder Beziehung erstellt wird, können Sie MERGE für alle drei Teile der Abfrage verwenden:

MERGE (p:Person {name: ‘Michael Cain’}) MERGE (m:Movie {title: ‘The Dark Knight’}) MERGE (p)-[:ACTED_IN]->(m) // oder in einer Zeile: MERGE (p:Person {name: ‘Michael Cain’})-[:ACTED_IN]->(m:Movie {title: ‘The Dark Knight’}) RETURN p, m

Was hier nach der Logik des Request-Handlers passiert:

  1. Neo4j versucht, eine Personenentität namens Michael Cain zu finden;

  2. Wenn eine Entität gefunden wird, betrachtet Neo4j alle ihre ACTED_IN-Beziehungen;

  3. Neo4j sucht dann unter diesen Links nach einem Film namens The Dark Knight.

Wenn zumindest in einer dieser Phasen keine Objekte gefunden wurden, wird das gesamte Muster erstellt. Das heißt, selbst wenn der Film The Dark Knight existiert, aber der Schauspieler Michael Cain nicht existiert, wird ein neuer Film mit diesem Namen erstellt. Dies ist das wichtigste Merkmal, das berücksichtigt werden muss, um eine Datenduplizierung zu vermeiden.

Versuchen wir, dies zu reproduzieren:

// Führe die Anfrage zum Hinzufügen von Schauspielern zum selben Film dreimal aus MERGE (p:Person {name: ‘Yuri Nikulin’})-[:ACTED_IN]->(m:Movie {title: ‘The Diamond Arm’}) RETURN p, m MERGE (p:Person {name: ‘Nina Grebeshkova’})-[:ACTED_IN]->(m:Movie {title: ‘The Diamond Arm’}) RETURN p, m MERGE (p:Person {name: ‘Andrei Mironov’})-[:ACTED_IN]->(m:Movie {title: ‘The Diamond Arm’}) RETURN p, m // Finde alle Datensätze mit diesem Filmtitel MATCH (m:Movie {title: ‘The Diamond Arm’})<-[:ACTED_IN]-(p:Person) ZURÜCK m,pEs ist nicht genau das geworden, was wir wollten.Es ist nicht genau das geworden, was wir wollten.

Die Lösung für einen solchen Fall kann darin bestehen, alle Entitäten separat zu erstellen und dann die Beziehungen zwischen ihnen zu trennen. Alles getrennte Anfragen.

Ein komplexeres Beispiel zum Erstellen von Mustern:

// In unserer Datenbank haben Oliver Stone und Rob Reiner noch nie zusammengearbeitet, // also haben sie keinen gemeinsamen Film. // // In dieser Abfrage suchen wir nach beiden // und erstellen einen neuen großartigen Film ohne Titel für sie 🙂 MATCH (oliver:Person {name: ‘Oliver Stone’}), (reiner:Person {name: ‘Rob Reiner’}) MERGE (oliver)-[:DIRECTED]->(Film:Film)<-[:ACTED_IN]-(reiner) RETURN-Film

Es ist auch nützlich zu wissen, dass das Schlüsselwort SET zum Hinzufügen und Aktualisieren von Attributen verwendet wird:

MATCH(p:Person)-[r:ACTED_IN]->(m:Movie) WO p.name=”Michael Cain” UND m.title=”The Dark Knight” SET r.roles = [‘Alfred Penny’]r.year = 2008 RETURN p, r, m

Löschen von Daten

Dies ist vielleicht der einfachste Abschnitt, denn Brechen ist nicht Bauen 🙂

Die wichtigste Erkenntnis hier ist, dass Sie einen Knoten nicht löschen können, solange er mindestens eine Verbindung hat.

Löschen wir alle Filme mit dem Namen The Diamond Arm, die wir zuvor erstellt haben:

MATCH (p:Person) WHERE p.name=”Jane Doe” DELETE pHoppla!Hoppla!

Okay, Sie können nicht löschen, solange Verbindungen bestehen. Um dies schnell zu beheben, haben wir das Schlüsselwortpaar DETACH DELETE. Aber wenn wir damit Filme löschen, dann werden wir darin nie Schauspieler finden, die wir auch löschen möchten.

Dann entfernen wir zuerst die Schauspieler, dann die doppelten Filme selbst:

// Trennen (DETACH) und Entfernen von Schauspielern aus Filmen namens The Diamond Arm MATCH (m:Movie {title:’The Diamond Arm’})<-[:ACTED_IN]-(p:Person) DETACH DELETE p // Lösche die doppelten Filme selbst namens The Diamond Arm. // Trennen (DETACH) ist nicht mehr notwendig, weil Schauspieler zusammen mit Links // wir haben gerade MATCH gelöscht (m:Movie {title:'The Diamond Arm'}) DELETE m

Um Attribute zu entfernen, können Sie sie einfach auf null setzen oder das Schlüsselwort REMOVE explizit aufrufen:

// Like this MATCH (p:Person) WHERE p.name=”Gene Hackman” SET p.born = null RETURN p // Oder like this MATCH (p:Person)-[r:ACTED_IN]->(m:Movie) WHERE p.name=”Michael Cain” AND m.title=”The Dark Knight” REMOVE r.roles RETURN p, r, m

Fazit

Wie Sie an den obigen Beispielen sehen können, ist die Arbeit mit Graphdatenbanken recht einfach, aber gleichzeitig ist es ungewöhnlich, dass jemand, der viel Zeit mit SQL verbringt, seine Denkweise ein wenig ändern muss.

Und wie das geht, verrate ich dir in den folgenden Artikeln 😉

Similar Posts

Leave a Reply

Your email address will not be published.