Die Abfragesprache Cypher wurde ursprΓΌnglich speziell fΓΌr das grafische DBMS Neo4j entwickelt . Cyphers Ziel ist es, eine fΓΌr Menschen lesbare SQL-Datenbank-Abfragesprache fΓΌr Graphendatenbanken bereitzustellen. Heutzutage wird Cypher von mehreren Graph-DBMS unterstΓΌtzt. OpenCypher wurde erstellt, um Cypher zu standardisieren.
Die Grundlagen der Arbeit mit dem Neo4j-DBMS werden im Artikel Grundlagen der Arbeit mit Neo4j in einem Browser beschrieben .
Betrachten Sie zum Kennenlernen von Cypher ein Beispiel eines Stammbaums, der aus dem klassischen Prolog-Lehrbuch von I. Bratko entlehnt wurde. In diesem Beispiel wird gezeigt, wie Sie einem Diagramm Knoten und Links hinzufΓΌgen, ihnen Beschriftungen und Attribute zuweisen und Fragen stellen.

Lassen Sie uns also einen Stammbaum auf dem Bild unten zeigen.

Mal sehen, wie man das entsprechende Diagramm in Cypher erstellt:
CREATE (pam:Person {name: "Pam"}), (tom:Person {name: "Tom"}), (kate:Person {name: "Kate"}), (mary:Person {name: "Mary"}), (bob:Person {name: "Bob"}), (liz:Person {name: "Liz"}), (dick:Person {name: "Dick"}), (ann:Person {name: "Ann"}), (pat:Person {name: "Pat"}), (jack:Person {name: "Jack"}), (jim:Person {name: "Jim"}), (joli:Person {name: "Joli"}), (pam)-[:PARENT]->(bob), (tom)-[:PARENT]->(bob), (tom)-[:PARENT]->(liz), (kate)-[:PARENT]->(liz), (mary)-[:PARENT]->(ann), (bob)-[:PARENT]->(ann), (bob)-[:PARENT]->(pat), (dick)-[:PARENT]->(jim), (ann)-[:PARENT]->(jim), (pat)-[:PARENT]->(joli), (jack)-[:PARENT]->(joli)
Eine CREATE-Anforderung zum HinzufΓΌgen von Daten zu einem grafischen DBMS besteht aus zwei Teilen: HinzufΓΌgen von Knoten und HinzufΓΌgen von VerknΓΌpfungen zwischen diesen. Jedem hinzuzufΓΌgenden Knoten wird im Rahmen dieser Anfrage ein Name zugewiesen, ΓΌber den dann VerknΓΌpfungen erstellt werden. Knoten und Kommunikationen kΓΆnnen Dokumente speichern. In unserem Fall enthalten die Knoten Dokumente mit den Namensfeldern und die DokumentverknΓΌpfungen nicht. Auch Knoten und Links kΓΆnnen beschriftet werden. In unserem Fall haben die Knoten die Bezeichnung Person und die VerknΓΌpfungen sind PARENT. Die Bezeichnung in Anforderungen wird durch einen Doppelpunkt vor dem Namen hervorgehoben.
Also sagte uns Neo4j: Es wurden Added 12 labels, created 12 nodes, set 12 properties, created 11 relationships, completed after 9 ms.
Mal sehen, was wir haben:
MATCH (p:Person) RETURN p

Niemand verbietet uns, das Erscheinungsbild des resultierenden Graphen zu bearbeiten:

Was kann man damit machen? Sie kΓΆnnen ΓΌberprΓΌfen, ob es sich beispielsweise um Pam handelt
Bobs Eltern:
MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Bob"}) RETURN ans
Wir erhalten den entsprechenden Untergraphen:

Dies ist jedoch nicht genau das, was wir brauchen. Γndern Sie die Anfrage:
MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Bob"}) RETURN ans IS NOT NULL
Jetzt als Antwort werden wir true
. Und wenn wir fragen:
MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Liz"}) RETURN ans IS NOT NULL
Wir bekommen nichts ... Hier mΓΌssen Sie das Wort OPTIONAL
, wenn
Das Ergebnis ist leer, dann wird false
zurΓΌckgegeben:
OPTIONAL MATCH ans = (:Person {name: "Pam"})-[:PARENT]->(:Person {name: "Liz"}) RETURN ans IS NOT NULL
Jetzt bekommen wir die erwartete Antwort false
.
Als nΓ€chstes kΓΆnnen Sie sehen, wer der Elternteil von wem ist:
MATCH (p1:Person)-[:PARENT]->(p2:Person) RETURN p1, p2
Γffnen Sie die Ergebnisregisterkarte mit Text
und sehen Sie eine Tabelle mit zwei Spalten:
βββββββββββββββββ€ββββββββββββββββ β"p1" β"p2" β βββββββββββββββββͺββββββββββββββββ‘ β{"name":"Pam"} β{"name":"Bob"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Tom"} β{"name":"Bob"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Tom"} β{"name":"Liz"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Kate"}β{"name":"Liz"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Mary"}β{"name":"Ann"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Bob"} β{"name":"Ann"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Bob"} β{"name":"Pat"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Dick"}β{"name":"Jim"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Ann"} β{"name":"Jim"} β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Pat"} β{"name":"Joli"}β βββββββββββββββββΌββββββββββββββββ€ β{"name":"Jack"}β{"name":"Joli"}β βββββββββββββββββ΄ββββββββββββββββ
Was kΓΆnnen wir noch lernen? Zum Beispiel, wer ist der Elternteil eines bestimmten Mitglieds der Gattung, zum Beispiel fΓΌr Bob:
MATCH (parent:Person)-[:PARENT]->(:Person {name: "Bob"}) RETURN parent.name
βββββββββββββββ β"parent.name"β βββββββββββββββ‘ β"Tom" β βββββββββββββββ€ β"Pam" β βββββββββββββββ
Als Antwort fordern wir hier nicht den gesamten Knoten an, sondern nur dessen spezifisches Attribut.
Wir kΓΆnnen auch herausfinden, wer Bobs Kinder sind:
MATCH (:Person {name: "Bob"})-[:PARENT]->(child:Person) RETURN child.name
ββββββββββββββ β"child.name"β ββββββββββββββ‘ β"Ann" β ββββββββββββββ€ β"Pat" β ββββββββββββββ
Wir kΓΆnnen auch fragen, wer Kinder hat:
MATCH (parent:Person)-[:PARENT]->(:Person) RETURN parent.name
βββββββββββββββ β"parent.name"β βββββββββββββββ‘ β"Pam" β βββββββββββββββ€ β"Tom" β βββββββββββββββ€ β"Tom" β βββββββββββββββ€ β"Kate" β βββββββββββββββ€ β"Mary" β βββββββββββββββ€ β"Bob" β βββββββββββββββ€ β"Bob" β βββββββββββββββ€ β"Dick" β βββββββββββββββ€ β"Ann" β βββββββββββββββ€ β"Pat" β βββββββββββββββ€ β"Jack" β βββββββββββββββ
Hmm, Tom und Bob haben sich zweimal getroffen.
MATCH (parent:Person)-[:PARENT]->(:Person) RETURN DISTINCT parent.name
Wir haben das Wort DISTINCT
zum RΓΌckgabeergebnis der Abfrage hinzugefΓΌgt, was bedeutet
Γ€hnlich wie in SQL.
βββββββββββββββ β"parent.name"β βββββββββββββββ‘ β"Pam" β βββββββββββββββ€ β"Tom" β βββββββββββββββ€ β"Kate" β βββββββββββββββ€ β"Mary" β βββββββββββββββ€ β"Bob" β βββββββββββββββ€ β"Dick" β βββββββββββββββ€ β"Ann" β βββββββββββββββ€ β"Pat" β βββββββββββββββ€ β"Jack" β βββββββββββββββ
MΓΆglicherweise stellen Sie auch fest, dass Neo4j die Eltern in der Reihenfolge an uns zurΓΌckgibt, in der sie in der CREATE
Anforderung eingegeben wurden.
Fragen wir nun, wer GroΓvater oder GroΓmutter ist:
MATCH (grandparent:Person)-[:PARENT]->()-[:PARENT]->(:Person) RETURN DISTINCT grandparent.name
GroΓartig, das wars:
ββββββββββββββββββββ β"grandparent.name"β ββββββββββββββββββββ‘ β"Tom" β ββββββββββββββββββββ€ β"Pam" β ββββββββββββββββββββ€ β"Bob" β ββββββββββββββββββββ€ β"Mary" β ββββββββββββββββββββ
In der Abfragevorlage haben wir einen namenlosen Zwischenknoten ()
und zwei Relationen vom Typ PARENT
.
Wir finden jetzt heraus, wer der Vater ist. Der Vater ist ein Mann, der ein Kind hat. Daher fehlen uns Daten darΓΌber, wer der Mann ist. Um festzustellen, wer eine Mutter ist, mΓΌssen Sie daher wissen, wer eine Frau ist. FΓΌgen Sie die relevanten Informationen zu unserer Datenbank hinzu. Zu diesem Zweck weisen wir den vorhandenen Knoten die Bezeichnungen Male
und Female
zu.
MATCH (p:Person) WHERE p.name IN ["Tom", "Dick", "Bob", "Jim", "Jack"] SET p:Male
MATCH (p:Person) WHERE p.name IN ["Pam", "Kate", "Mary", "Liz", "Ann", "Pat", "Joli"] SET p:Female
Lassen Sie uns erklΓ€ren, was wir hier gemacht haben: Wir haben alle Knoten mit der Bezeichnung Person
und ΓΌberprΓΌft
die Namenseigenschaft gemÀà der in eckigen Klammern angegebenen Liste und den entsprechenden Knoten die Bezeichnung Male
bzw. Female
.
ΓberprΓΌfen Sie:
MATCH (p:Person) WHERE p:Male RETURN p.name
ββββββββββ β"p.name"β ββββββββββ‘ β"Tom" β ββββββββββ€ β"Bob" β ββββββββββ€ β"Dick" β ββββββββββ€ β"Jack" β ββββββββββ€ β"Jim" β ββββββββββ
MATCH (p:Person) WHERE p:Female RETURN p.name
ββββββββββ β"p.name"β ββββββββββ‘ β"Pam" β ββββββββββ€ β"Kate" β ββββββββββ€ β"Mary" β ββββββββββ€ β"Liz" β ββββββββββ€ β"Ann" β ββββββββββ€ β"Pat" β ββββββββββ€ β"Joli" β ββββββββββ
Wir haben alle Knoten mit der Bezeichnung Person
angefordert, die auch die Bezeichnung Male
bzw. Female
haben. Aber wir kΓΆnnten unsere Anfragen ein wenig anders stellen:
MATCH (p:Person:Male) RETURN p.name MATCH (p:Person:Female) RETURN p.name
Schauen wir uns noch einmal unser Diagramm an:

Neo4j Browser hat die Knoten in zwei verschiedenen Farben gemalt, entsprechend den Markierungen von Male und
Weiblich
Ok, jetzt kΓΆnnen wir alle VΓ€ter aus der Datenbank abfragen:
MATCH (p:Person:Male)-[:PARENT]->(:Person) RETURN DISTINCT p.name
ββββββββββ β"p.name"β ββββββββββ‘ β"Tom" β ββββββββββ€ β"Bob" β ββββββββββ€ β"Dick" β ββββββββββ€ β"Jack" β ββββββββββ
Und MΓΌtter:
MATCH (p:Person:Female)-[:PARENT]->(:Person) RETURN DISTINCT p.name
ββββββββββ β"p.name"β ββββββββββ‘ β"Pam" β ββββββββββ€ β"Kate" β ββββββββββ€ β"Mary" β ββββββββββ€ β"Ann" β ββββββββββ€ β"Pat" β ββββββββββ
Formulieren wir nun eine Bruder-Schwester-Beziehung. X ist Bruder von Y,
Wenn er ein Mann ist und fΓΌr X und Y gibt es mindestens einen gemeinsamen Elternteil. Γhnliches gilt fΓΌr
Beziehungsschwester.
Bruder Attitude ΓΌber Cypher:
MATCH (brother:Person:Male)<-[:PARENT]-()-[:PARENT]->(p:Person) RETURN brother.name, p.name
ββββββββββββββββ€βββββββββ β"brother.name"β"p.name"β ββββββββββββββββͺβββββββββ‘ β"Bob" β"Liz" β ββββββββββββββββ΄βββββββββ
Schwester Haltung zu Cypher:
MATCH (sister:Person:Female)<-[:PARENT]-()-[:PARENT]->(p:Person) RETURN sister.name, p.name
βββββββββββββββ€βββββββββ β"sister.name"β"p.name"β βββββββββββββββͺβββββββββ‘ β"Liz" β"Bob" β βββββββββββββββΌβββββββββ€ β"Ann" β"Pat" β βββββββββββββββΌβββββββββ€ β"Pat" β"Ann" β βββββββββββββββ΄βββββββββ
So kΓΆnnen wir herausfinden, wer wessen Elternteil ist und wer wessen GroΓvater oder GroΓmutter ist. Aber was ist mit den entfernteren Vorfahren? Mit UrgroΓvΓ€tern, UrurgroΓvΓ€tern oder so weiter? Wir werden nicht fΓΌr jeden dieser FΓ€lle eine entsprechende Regel schreiben, und sie wird jedes Mal problematischer. TatsΓ€chlich ist alles einfach: X ist ein Vorfahr fΓΌr Y, wenn es ein Vorfahr fΓΌr ein ΓΌbergeordnetes Y ist. Cypher bietet ein Muster *
, mit dem Sie eine Folge von Beziehungen beliebiger LΓ€nge anfordern kΓΆnnen:
MATCH (p:Person)-[*]->(s:Person) RETURN DISTINCT p.name, s.name
Es gibt wirklich ein Problem dabei: Es wird irgendwelche Verbindungen geben. FΓΌgen Sie einen Verweis auf den Link PARENT
:
MATCH (p:Person)-[:PARENT*]->(s:Person) RETURN DISTINCT p.name, s.name
Um die LΓ€nge des Artikels nicht zu vergrΓΆΓern, finden wir alle Vorfahren von Joli
:
MATCH (p:Person)-[:PARENT*]->(:Person {name: "Joli"}) RETURN DISTINCT p.name
ββββββββββ β"p.name"β ββββββββββ‘ β"Jack" β ββββββββββ€ β"Pat" β ββββββββββ€ β"Bob" β ββββββββββ€ β"Pam" β ββββββββββ€ β"Tom" β ββββββββββ
Betrachten Sie eine komplexere Regel, um herauszufinden, wer mit wem verwandt ist.
Erstens sind Verwandte Vorfahren und Nachkommen, zum Beispiel ein Sohn und eine Mutter, eine GroΓmutter und ein Enkel. Zweitens sind Verwandte BrΓΌder und Schwestern, einschlieΓlich Cousins, Second Cousins ββund so weiter, was in Bezug auf Vorfahren bedeutet, dass sie einen gemeinsamen Vorfahren haben. Und drittens gelten Verwandte, die gemeinsame Nachkommen haben, zum Beispiel Ehemann und Ehefrau, als Verwandte.
In Cypher mΓΌssen Sie UNION
fΓΌr viele Muster verwenden:
MATCH (r1:Person)-[:PARENT*]-(r2:Person) RETURN DISTINCT r1.name, r2.name UNION MATCH (r1:Person)<-[:PARENT*]-(:Person)-[:PARENT*]->(r2:Person) RETURN DISTINCT r1.name, r2.name UNION MATCH (r1:Person)-[:PARENT*]->(:Person)<-[:PARENT*]-(r2:Person) RETURN DISTINCT r1.name, r2.name
Hier werden in der ersten Regel Verbindungen verwendet, deren Richtung fΓΌr uns unerheblich ist. Eine solche Verbindung ist ohne Pfeil, nur mit einem Strich angedeutet -
. Die zweite und dritte Regel sind offensichtlich und vertraut geschrieben.
Wir geben hier nicht das Ergebnis der Gesamtabfrage an, sondern sagen nur, dass es sich bei den gefundenen Verwandtenpaaren um 132 handelt, was mit dem berechneten Wert als Anzahl der geordneten Paare von 12 ΓΌbereinstimmt. Wir kΓΆnnten diese Abfrage auch angeben, indem wir das Vorkommen der Variablen r1
oder r2
durch (:Person {name: "Liz"})
ist jedoch in unserem Fall nicht sehr sinnvoll, da alle Personen in unserer Datenbank offensichtlich Verwandte sind.
Dies schlieΓt unsere Diskussion ΓΌber die Identifizierung von Beziehungen zwischen Personen in unserer Datenbank ab.
Zuletzt ΓΌberlegen Sie, wie Sie Knoten und VerknΓΌpfungen entfernen.
Um alle unsere Personen zu lΓΆschen, kΓΆnnen Sie die Anfrage ausfΓΌhren:
MATCH (p:Person) DELETE p
Neo4j teilt uns jedoch mit, dass Sie keine Knoten mit Links lΓΆschen kΓΆnnen.
Daher lΓΆschen wir zuerst die Links und wiederholen dann das Entfernen von Knoten:
MATCH (p1:Person)-[r]->(p2:Person) DELETE r
Was wir jetzt gemacht haben: Zwei Personen, zwischen denen eine Verbindung besteht, verglichen, diese Verbindung als r
und dann gelΓΆscht.
Fazit
Der Artikel zeigt anhand eines einfachen Beispiels fΓΌr ein soziales Diagramm, wie die Funktionen der Cypher-Abfragesprache verwendet werden. Insbesondere haben wir untersucht, wie Sie Knoten und Links mit einer Abfrage hinzufΓΌgen, nach verwandten Daten suchen, einschlieΓlich indirekter Links, und wie Sie Knoten Bezeichnungen zuweisen. Weitere Informationen zu Cypher finden Sie unter den folgenden Links. Ein guter Ausgangspunkt ist die "Neo4j Cypher Refcard".
Neo4j ist bei weitem nicht das einzige Graph-DBMS. Zu den bekanntesten zΓ€hlen Cayley , Dgraph mit GraphQL-Abfragesprache, Multi-Model- ArangoDB und OrientDB . Von besonderem Interesse ist mΓΆglicherweise Blazegraph mit UnterstΓΌtzung fΓΌr RDF und SPARQL.
Referenzen
Bibliographie
- Robinson Jan, Weber Jim und Eifrem Emil. Graph-Datenbanken. Neue Funktionen
fΓΌr die Arbeit mit verwandten Daten / Per. aus dem Englischen - 2nd ed. - M .: DMK-Press,
2016 - 256 s. - Bratko I. Programmierung in Prologsprache fΓΌr kΓΌnstliche Intelligenz:
trans. aus dem Englischen - M .: Mir, 1990 .-- 560 S.: krank.
Nachwort
Der Autor des Artikels kennt nur zwei Unternehmen (beide aus St. Petersburg), die graphische DBMS fΓΌr ihre Produkte verwenden. Aber ich wΓΌrde gerne wissen, wie viele Unternehmen von Lesern dieses Artikels sie in ihrer Entwicklung verwenden. Daher schlage ich vor, an der Umfrage teilzunehmen. Schreiben Sie auch ΓΌber Ihre Erfahrungen in den Kommentaren, es wird sehr interessant zu wissen sein.