SQL- und NoSQL-Datenbanken

Eine Datenbank mit Neo4j erstellen

Schritt 1: Entitäten-Beziehungsmodell entwickeln

Schritt 2: Graphenmodell entwerfen

Schritt 3: Neo4j einrichten

Schritt 4: Graphenstruktur in Neo4j definieren

Schritt 5: Knoten und Kanten eingeben

Schritt 6: Geschäftsvorfälle erfassen

Schritt 7: Daten ändern und löschen

Schritt 8: Datenbank mit Cypher auswerten

Schritt 9: Komplexere Abfragen erfassen

Eine Datenbank mit Neo4j erstellen

Mit dieser Anleitung können Sie ein einfaches Datenbankprojekt aus der Reisebranche selbstständig durchspielen. Ausgehend von einem Entitäten-Beziehungsmodell werden Sie die Knoten und Kanten der Datenbank herleiten und in Neo4j definieren. Nachdem Sie die den Graphen mit Knoten und Kanten gefüllt haben, können Sie mit selbst formulierten Abfragen die wichtigsten Informationen aus der Datenbank extrahieren.

Neo4j ist ein Softwareprodukt mit einem eingebauten Webserver, welcher eine grafische Bedienungsoberfläche in Form einer interaktiven Webseite zur Verfügung stellt. Diese Oberfläche erlaubt es, die Knoten und Kanten mit Hilfe von Cypher-Befehlen zu verwalten.

Die Elemente einer Neo4j-Datenbank werden mit Hilfe einer Konsole verwaltet, wie der Blick auf eine geöffnete Neo4j-Datenbank zeigt:

Im Beispiel wird die Begrüssungsnachricht angezeigt, welche hilfreiche Informationen darüber liefert, wie Neo4j verwendet werden kann.

Die Oberfläche bietet folgende Elemente:

  • Eine Menüleiste auf der linken Seite, die schnellen Zugriff zu Informationen und Standardbefehlen bietet.
  • Eine Konsole am oberen Rand, die es erlaubt, die Knoten und Kanten zu verwalten.
  • Einem Ausgabestrom, welches den Rest der Oberfläche füllt und die Ausgaben der jeweiligen Befehlen anzeigt.

In dieser Anleitung beziehen sich die Abbildungen und Befehle auf die englische Version von Neo4j 2.2.3; es sollte Ihnen aber nicht schwerfallen, den Bezug zu anderen Versionen herzustellen.

Zur Fallstudie travelblitz

Als Beispiel realisieren Sie eine Datenbankanwendung für das Reisebüro travelblitz, das sich auf die Vermietung von Ferienhäusern auf griechischen Inseln spezialisiert hat. Die Ferienhäuser befinden sich auf verschiedenen Inseln. Es ist damit zu rechnen, dass in Zukunft weitere Häuser auf neuen Inseln dazukommen. Momentan werden Kunden- und Häuserdaten traditionell mit der Hilfe eines Karteisystems verwaltet, die Abfragemöglichkeiten sind entsprechend eingeschränkt. Beispielsweise ist es zeitraubend herauszufinden, welche Häuser weniger als 400 Euro pro Woche kosten und in einem bestimmten Zeitraum (z.B. für die ersten drei Juliwochen) frei sind. Sie möchten sich nun besser auf die Kundenanfragen einstellen und beschliessen, den Missstand durch den Einsatz einer Graphendatenbank zu beseitigen.

Schritt 1: Entitäten-Beziehungsmodell entwickeln

Für die Erstellung eines Entitäten-Beziehungsmodells treffen Sie die folgenden vereinfachenden Annahmen:

  1. Die Saison dauert von Woche 10 bis 40, d.h. von Anfang April bis Ende September. Der Mietpreis ist während der gesamten Saison konstant; die Häuser werden  wochenweise vermietet.
  2. Eine Buchung enthält die folgenden Informationen: Haus, Kunde und Nummer der Woche. Falls ein Kunde ein Haus mehrere Wochen hintereinander mietet, müssen mehrere Buchungen angelegt werden (eine pro Woche).
  3. Der Zeitraum jeder Buchung, d.h. die betreffende Woche, wird in Form einer Zahl zwischen 10 und 40 angegeben. Für jedes Jahr wird eine neue Datenbank angelegt.
  4. Die Datenbank enthält vorläufig keinerlei Informationen über Zahlungsfristen, Rechnungen usw.

Diese Annahmen dienen dazu, das Datenmodell zu Übungszwecken so klein wie möglich zu halten. Sie sind nun aufgefordert, das Entitäten-Beziehungsmodell für travelblitz zu entwickeln: Welche Entitätsmengen und Beziehungsmengen legen Sie fest? Welche Merkmale ordnen Sie den Entitätsmengen zu, welche den Beziehungsmengen? Welche Identifikationsschlüssel sehen Sie für die Entitätsmengen vor?

Mit den Entitätsmengen KUNDE, HAUS und INSEL legen Sie das Entitäten-Beziehungsmodell für die Ferienhaus-Verwaltung fest. Die Beziehungsmenge BELEGUNG zeigt Ihnen die Ausleihe der Ferienhäuser an die Kunden; die Beziehung ist komplex-komplex. Das Merkmal Woche haben Sie als typisches Beziehungsmerkmal erkannt, da es die Belegung eines Ferienhauses durch einen Kunden zeitlich festlegt. Schliesslich drücken Sie die hierarchische Zuordnung der Ferienhäuser zu den Inseln mit der Beziehungsmenge LAGE aus.

Schritt 2: Graphenmodell entwerfen

Nun stellen Sie sich folgende Fragen: Wie sieht das Graphenmodell für die Ferienhaus-Verwaltung aus ? Welche Abbildungsregeln verwenden Sie, um das obige Entitäten-Beziehungsmodell in Kanten und Knoten zu überführen?

Aus dem Entitäten-Beziehungsmodell leiten Sie gemäss Abschnitt 2.4.2 das Graphenmodell der Datenbank her :

  1. Der Abbildungsregel 1 folgend müssen Sie für jede Entitätsmenge einen eigenständigen Knoten festlegen. Als Namen für die Knoten wählen Sie der Einfachheit halber die Namen der entsprechenden Entitätsmengen. Die Merkmale der Entitätsmengen werden als Eigenschaften der Knoten geführt.
  2. Gemäss der Abbildungsregel 2 kann die netzwerkartige Beziehungsmenge BELEGUNG durch eine ungerichtete Kanten ausgedrückt werden. Das Merkmal Woche, wird als Eigenschaft der Kante geführt.
    Alternativ: Gemäss der Abbildungsregel 3 kann die netzwerkartige Beziehungsmenge BELEGUNG durch zwei gerichtete Kanten ausgedrückt werden. Die Assoziationen liefern dabei die Namen für die Kanten. Die von KUNDE nach HAUS gerichtete Kante hat den Namen BELEGT und  die von HAUS nach  KUNDE gerichtete Kante hat den Namen BELEGT_VON. Das Merkmal Woche, wird als Eigenschaft der Kanten geführt. Die entsprechenden Assoziationstypen werden an den Pfeilspitzen geführt. Beim zweiten Ansatz müssen Sie sich bewusst sein, dass evtl. Redundanzen entstehen. So würde das Merkmal Woche bei beiden Kanten die selbe Information enthalten. Dieser Ansatz wird hier als gestrichelte Kanten angezeigt, aber für die Umsetzung nicht berücksichtigt.
  3. Gemäss der Abbildungsregel 4 kann die hierarchische Beziehungsmenge LAGE durch eine gerichtete Kanten ausgedrückt werden. Die Richtung wird vom Wurzelknoten, der Entitätsmenge INSEL, zum Blattknoten, der Entitätsmenge HAUS, gewählt. Der mehrfache Assoziationstyp wird an der Pfeilspitze annotiert.
    Alternativ: Gemäss der Abbildungsregel 2 kann die hierarchische Beziehungsmenge LAGE durch eine ungerichtete Kanten ausgedrückt werden. Dieser Ansatz wird hier als gestrichelte Kante angezeigt, aber für die Umsetzung nicht berücksichtigt.

Schritt 3: Neo4j einrichten

Befolgen Sie folgende Schritte um die Neo4j Graphendatenbank einzurichten:

  1. Navigieren Sie zu folgender Webseite und laden Sie die Comunity  Edition der  Neo4j Datenbank herunter: http://neo4j.com/download/
  2. Entpacken Sie  die  das  Archiv  und  befolgen  Sie  die Schritte im darin enthaltenen README.txt, um den Datenbankserver zu starten.
  3. Navigieren Sie  mit  ihrem  Webbrowser  zu  folgender  Adresse, um auf die grafische Oberfläche zugreifen zu können: http://localhost:7475/
  4. Melden Sie sich an mit Benutzername “neo4j” und Passwort “neo4j”. Das Passwort muss beim ersten Anmelden geändert werden.
  5. Sie sind nun bereit, die Knoten und Kanten in der Datenbank zu verwalten.

Schritt 4: Graphenstruktur in Neo4j definieren

Lose Struktur

Im Gegensatz zu relationalen Datenbanken wird bei der Neo4j Graphendatenbank keine  fixe Struktur festgelegt, der die Knoten und Kanten dann entsprechen müssten. Dies hat den Vorteil, dass man bei der Vernetzung der Knoten flexibel ist, doch die Gesamtstruktur kann stark darunter leiden. Es empfiehlt sich, im Voraus eine klare Struktur auszuarbeiten und sich bei der Erstellung der Knoten und Kanten an diese Struktur zu halten.

Labels

Die Knoten können mit sogenannten Labels in verschiedene Kategorien eingeteilt werden. Die Labels können jedoch nicht im Voraus erstellt werden, sondern erst bei der Erstellung der Knoten, die das entsprechende Label erhalten.

Verwenden Sie die Labels KUNDE, HAUS und INSEL, um die Knoten gemäss der oben definierten Graphenstruktur zu sortieren.

IDs

Die Knoten und Kanten erhalten automatisch eine ID bei der Erstellung. Anhand dieser ID, welche mit der Funktion id() abgerufen werden kann, könnte man die Knoten und Kanten eindeutig auswählen. Merkmale wie KundenId, HausId und InselId wären also nicht nötig. Behalten Sie sie jedoch trotzdem bei, denn diese Namen sind aussagekräftiger und vereinfachen somit die Arbeit.

Um zu garantieren, dass jede ID eindeutig ist, können folgende Cypher-Befehle einzeln in der Konsole ausgeführt werden, welche für die entsprechenden Labels und Eigenschaften eine Einschränkung festlegen:

CREATE CONSTRAINT ON (k:KUNDE) ASSERT k.KundenId IS UNIQUE;
CREATE CONSTRAINT ON (h:HAUS) ASSERT h.HausId IS UNIQUE;
CREATE CONSTRAINT ON (i:INSEL) ASSERT i.InselId IS UNIQUE; 

Richtung der Kanten

Neo4j kennt nur Kanten mit genau einer Richtung. Ungerichtete Kanten können nicht erstellt werden. Für die Praxis spielt dies jedoch keine Rolle, denn ungerichtete Kanten können simuliert werden, indem bei der Erstellung die Richtung willkürlich gewählt wird. Die Abfrage muss dann jedoch so formuliert werden, dass sie die Richtung nicht berücksichtigt.

Muster, welche gerichteten Kanten entsprechen, sehen wie folgt aus: () <- ­[] – ­() oder () – ­[] -­> (). Ein Muster, welches ungerichteten Kanten entspricht, bzw. die Richtung nicht berücksichtigt, sieht wie folgt aus: () – ­[] -­ ().

Vermeiden Sie hier für eine einzige Beziehung zwei Kanten mit entgegen gesetzten Richtungen zu verwenden. Stattdessen sollte eine einzelne, ungerichtete Kante verwendet werden, wie oben beschrieben wurde.

Schritt 5: Knoten und Kanten eingeben

Die Knoten und Kanten können mit Hilfe von Cypher-Befehlen über die Konsole erstellt, abgeändert und gelöscht werden.

Die Syntax, um einen Knoten zu erstellen, sieht wie folgt aus:

CREATE (Variable:LABEL {"eigenschaft1":"wert", "eigenschaft2":1234, "eigenschaft3":true}) 
RETURN variable; 

Die runden Klammern legen fest, dass es sich um einen Knoten handelt. Anhand der Variable kann der erstellte Knoten in derselben Abfrage weiter manipuliert werden; hier wird er zur Kontrolle mit RETURN ausgegeben. Die Eigenschaften werden von geschweiften Klammern umschlossen. Der Name der Eigenschaft ist als String auszudrücken. Der Wert der Eigenschaft kann beispielsweise ein String, eine Zahl oder ein Boolean sein. Der Strichpunkt legt das Ende des Befehls fest.

Knoten erfassen

Geben Sie folgenden Befehl ein, um die erste Kundin hinzuzufügen:

CREATE (k:KUNDE {KundenId:1, Name:"Meier", Vorname:"Ursula", Anrede:"Frau", Strasse:"Lindenstr. 13", PLZ:4051, Ort:"Basel"}) 
RETURN k; 

Der erstellte Knoten wird sofort im Ausgabestrom angezeigt:

Geben Sie folgenden Befehl ein, um die restlichen Kunden hinzuzufügen. Die Ausgabe, also das RETURN, ist hier nicht mehr nötig und somit können Sie auch die Variable weglassen. Um mehrere Knoten in einem einzelnen Befehl hinzuzufügen, können mehrere CREATE Befehle verwendet werden.

CREATE (:KUNDE {KundenId:2, Name:"Aeaby", Vorname:"Paul", Anrede:"Herr", Strasse:"Rosenweg 26", PLZ:3001, Ort:"Bern"})
CREATE (:KUNDE {KundenId:3, Name:"Gessner", Vorname:"Heidi", Anrede:"Frau", Strasse:"Reichengasse 11", PLZ:1700, Ort:"Fribourg"})
CREATE (:KUNDE {KundenId:4, Name:"Zumsteg", Vorname:"Irene", Anrede:"Frau", Strasse:"Brückenstr. 23", PLZ:3005, Ort:"Bern"})
CREATE (:KUNDE {KundenId:5, Name:"Wyss", Vorname:"Beat", Anrede:"Herr", Strasse:"Wallisellenstr. 243. 13", PLZ:8050, Ort:"Zürich"}); 

Sobald alle Kunden erstellt sind, können sie mit folgendem Befehl angezeigt werden:

MATCH (k:KUNDE) RETURN *; 

Die Kunden werden nun als Knoten Graph angezeigt. Die Beschriftung der Knoten können Sie wählen, indem Sie am oberen Rand auf das Label KUNDE(5) klicken und anschliessend am unteren Rand eine Eigenschaft auswählen. Falls die Optionen am unteren Rand nicht angezeigt werden, mit dem kleinen Dreieck rechts unten expandiert werden.

Um eine Tabelle mit einer Auswahl an Informationen anzuzeigen, können Sie einen ähnlichen Befehl verwenden:

MATCH (k:KUNDE) RETURN k.Name, k.Vorname; 

Die Ausgabe sieht dann so aus:

Geben Sie nun den folgenden Befehl ein, um die Inseln hinzuzufügen.

CREATE (:INSEL {InselId:1, Inselname:"Rhodos", Besonderheiten:"Windsurfen"}) 
CREATE (:INSEL {InselId:2, Inselname:"Samos", Besonderheiten:"Golfplatz, Wandern"})
CREATE (:INSEL {InselId:3, Inselname:"Kreta", Besonderheiten:"historische Sehenswürdigkeiten, Felsklippen"}); 

Geben Sie folgenden Befehl ein, um die Häuser hinzuzufügen:

CREATE (h:HAUS {HausId:1, Hausname:"Paphos", Anz_Zimmer:3, Max_Personen:5, Meerblick:true, Miete:500})
CREATE (:HAUS {HausId:2, Hausname:"Arethoussa", Anz_Zimmer:2, Max_Personen:4, Meerblick:false, Miete:400})
CREATE (:HAUS {HausId:3, Hausname:"Malia", Anz_Zimmer:4, Max_Personen:6, Meerblick:true, Miete:750})
CREATE (:HAUS {HausId:4, Hausname:"Atrium", Anz_Zimmer:3, Max_Personen:4, Meerblick:true, Miete:450}); 

Gibt man nun alle Knoten aus, zeigt sich folgendes Bild:

MATCH (n) RETURN *; 

Testen Sie nun, ob die vereinbarte Regel, dass jede KundenId eindeutig sein muss, eingehalten bleibt. Erstellen Sie weitere Kunden mit einer bereits existierenden ID. Testen Sie dasselbe für die Inseln und Häuser.

Da die Knoten jetzt bereit sind, können Sie die Kanten erstellen.

Kanten erfassen

Der Befehl, um Kanten zu erstellen, setzt sich etwas anders zusammen, denn eine Kante kann nicht ohne die beiden inzidenten Knoten existieren. Man wählt also erst die Knoten, welche man verbinden möchte und speichert sie in einer Variable. Anschliessend erstellt man die entsprechende Kante zwischen diesen Knoten.

Geben Sie folgenden Befehl ein, um die erste Lage hinzuzufügen und um diese gleich anzuzeigen:

MATCH (h:HAUS), (i:INSEL) WHERE h.HausId = 1 AND i.InselId = 1 CREATE (h)<­-[l:LAGE]­-(i) RETURN l; 

Die Ausgabe enthält die erstellte Kante und die zwei inzidenten Knoten:

Geben Sie nun folgende Befehle Zeile für Zeile ein, um die restlichen Lagen  hinzuzufügen (die Ausgabe wird wieder weggelassen):

MATCH (h:HAUS), (i:INSEL) WHERE h.HausId = 2 AND i.InselId = 2 CREATE (h)<­-[l:LAGE]­-(i); 
MATCH (h:HAUS), (i:INSEL) WHERE h.HausId = 3 AND i.InselId = 1 CREATE (h)<­-[l:LAGE]­-(i); 
MATCH (h:HAUS), (i:INSEL) WHERE h.HausId = 4 AND i.InselId = 3 CREATE (h)<­-[l:LAGE]­-(i); 

Geben Sie schliesslich folgende Befehle Zeile für Zeile ein, um die Belegung hinzuzufügen:

MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 1 AND k.KundenId = 2 CREATE (h)­-[b:BELEGUNG {Woche:28}]­->(k); 
MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 1 AND k.KundenId = 2 CREATE (h)­-[b:BELEGUNG {Woche:29}]­->(k);
MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 1 AND k.KundenId = 4 CREATE (h)­-[b:BELEGUNG {Woche:31}]­->(k);
MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 1 AND k.KundenId = 4 CREATE (h)­-[b:BELEGUNG {Woche:32}]­->(k);
MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 1 AND k.KundenId = 4 CREATE (h)­-[b:BELEGUNG {Woche:33}]­->(k);
MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 2 AND k.KundenId = 5 CREATE (h)­-[b:BELEGUNG {Woche:17}]­->(k);
MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 2 AND k.KundenId = 1 CREATE (h)­-[b:BELEGUNG {Woche:31}]­->(k);
MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 2 AND k.KundenId = 1 CREATE (h)­-[b:BELEGUNG {Woche:32}]­->(k);
MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 4 AND k.KundenId = 3 CREATE (h)­-[b:BELEGUNG {Woche:25}]­->(k);
MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 4 AND k.KundenId = 3 CREATE (h)­-[b:BELEGUNG {Woche:26}]­->(k);
MATCH (h:HAUS), (k:KUNDE) WHERE h.HausId = 4 AND k.KundenId = 3 CREATE (h)­-[b:BELEGUNG {Woche:27}]­->(k); 

Geben Sie noch einmal den Befehl MATCH (n) RETURN *; ein, um den komplette Graph anzuzeigen:

Nun können Sie mit der Datenbank arbeiten und Geschäfte abwickeln.

Schritt 6: Geschäftsvorfälle erfassen

Beispielsweise möchten Sie Herrn Ernst Bircher, wohnhaft in der Seestrasse 10 in 6004 Luzern erfassen, der Ende August das Ferienhaus Malia für drei Wochen (Wochen 33 bis 35) buchen möchte. Tragen Sie diesen Geschäftsfall in Ihre Datenbank ein.

CREATE (k:KUNDE {KundenId:6, Name:"Bircher", Vorname:"Ernst", Anrede:"Herr", Strasse:"Seestrasse 10", PLZ:6004, Ort:"Luzern"});

MATCH (h:HAUS), (k:KUNDE)
WHERE h.Hausname = "Malia" AND k.KundenId = 6 
CREATE (h)­-[b:BELEGUNG {Woche:33}]-­>(k);

MATCH (h:HAUS), (k:KUNDE)
WHERE h.Hausname = "Malia" AND k.KundenId = 6 
CREATE (h)-­[b:BELEGUNG {Woche:34}]­->(k);

MATCH (h:HAUS), (k:KUNDE)
WHERE h.Hausname ="Malia" AND k.KundenId = 6 
CREATE (h)­-[b:BELEGUNG {Woche:35}]­->(k); 

Das Reisebüro travelblitz hat ein neues Ferienhaus mit dem Namen Pegasus auf der Insel Kreta akquiriert. Dieses Haus hat 5 Zimmer und kann maximal 8 Personen aufnehmen. Die Miete beträgt 650 Euro. Leider gibt es keine Sicht auf das Meer. Geben Sie nun all diese Angaben in die Datenbank ein.

CREATE (h:HAUS {HausId:5, Hausname:"Pegasus", Anz_Zimmer:5, Max_Personen:8, Meerblick:false, Miete:650});

MATCH (h:HAUS), (i:INSEL) WHERE h.Hausname = "Pegasus" AND i.Inselname = "Kreta" CREATE (h)<­-[l:LAGE]­-(i); 

Schritt 7: Daten ändern und löschen

Die Knoten und Kanten können nach ihrer Erstellung weiter bearbeitet oder gegebenenfalls gelöscht werden.

Erstellen Sie einen neuen Kunden mit KundenId 7 aber keinen weiteren Eigenschaften.

CREATE (k:KUNDE {KundenId:7}) RETURN k; 

Verwenden Sie nun den SET-Befehl, um diesem Kunden den Namen Albert Einstein zu geben.

MATCH (k:KUNDE) WHERE k.KundenId = 7 SET k.Vorname = "Albert" SET k.Name = "Einstein" RETURN k; 

Löschen Sie den Kunden schlussendlich mit dem DELETE Befehl.

MATCH (k:KUNDE) WHERE k.KundenId = 7 DELETE k; 

Schritt 8: Datenbank mit Cypher auswerten

In Neo4j können Sie Abfragen in Form von Cypher-Befehlen eingeben um Informationen aus der Datenbank abzufragen. Sie haben weiter oben schon einfache Abfragen gemacht, um zu kontrollieren, ob die Daten korrekt hinzugefügt wurden und um Daten zu manipulieren.

Nun werden Sie komplexere Befehle formulieren, um Fragen zu beantworten, wie: Welche Häuser befinden sich auf der Insel Kreta? Welches Haus hat die Kundin Ursula Meier gebucht? Welche Häuser sind in den Wochen 31 bis 33 frei? Welches Haus hat die Kundin Ursula Meier gebucht ?

Welches Haus hat die Kundin Ursula Meier gebucht ?

Um Buchungen einer bestimmten Person zu finden, können Sie die Eigenschaften Name und Vorname verwenden. Wird ein String als Name gegeben, wird nach genau diesem String gesucht.

MATCH (k:KUNDE)-[:BELEGUNG]-(h:HAUS)
WHERE k.Name = "Meier" AND k.Vorname = "Ursula" 
RETURN DISTINCT h.Hausname AS Hausname; 

Sind Sie sich der Schreibweise des Namens nicht sicher, können Sie auch sogenannte “regular expressions” verwenden. Es genügt dafür, dem Gleichheitszeichen eine Tilde anzuhängen und den fixen String durch eine regular expression zu ersetzen.

Sie sind sich beispielsweise nicht mehr sicher, ob man Meier oder Meyer schreibt:

MATCH (k:KUNDE)-[:BELEGUNG]-(h:HAUS)
WHERE k.Name =~ "Me(i|y)er" AND k.Vorname = "Ursula" 
RETURN DISTINCT h.Hausname AS Hausname; 

Liste aller Häuser mit Preisangaben :

Sie wünschen eine Liste aller Häuser mit Preisangaben, wobei die Häuser nach der Höhe des Mietpreises sortiert sind:

MATCH (h:HAUS)
RETURN h.Hausname AS Hausname, h.Miete AS Miete 
ORDER BY h.Miete; 

Liste aller Kunden aus der Ostschweiz

Sie  wünschen  eine  Liste  mit  Namen,  Vornamen,  Postleitzahl  und  Ort  aller  Kunden  aus  der Ostschweiz (mit Postleitzahl >= 3000).

MATCH (k:KUNDE) 
WHERE k.PLZ >= 3000
RETURN k.Name, k.Vorname, k.PLZ, k.Ort; 

Übersicht aller Häuser mit Inselangaben

Wünschen Sie eine Übersicht über alle Häuser mit den jeweiligen Inselangaben, können Sie mit folgenden Befehlen die Informationen als übersichtlichen Graph, respektive als ausführliche Tabelle abrufen:

MATCH (h:HAUS)­­--(i:INSEL) 
RETURN h, i; 
MATCH (h:HAUS)­­--(i:INSEL)
RETURN DISTINCT h.Hausname, i.Inselname, h.Anz_Zimmer, h.Max_Personen, h.Meerblick, h.Miete; 

Liste aller Buchungen

Verwenden Sie folgenden Befehl, um eine Liste aller Buchungen mit den Namen der Kunden inklusive der gebuchten Häuser und Wochenangaben abzufragen.

MATCH (k:KUNDE)-[b:BELEGUNG]-(h:HAUS)
RETURN k.Name, k.Vorname, h.Hausname, b.Woche 
ORDER BY h.Hausname, b.Woche; 

Aus diesem Beispiel wird gut ersichtlich, welche Vorteile eine Graphendatenbank mit sich bringen. Zum Vergleich ist die dieselbe Cypher-Abfrage noch einmal neben einer analogen SQL-Abfrage abgedruckt:

Cypher-Abfrage SQL-Abfrage
MATCH   (k:KUNDE)-[b:BELEGUNG]-(h:HAUS)
RETURN   k.Name, k.Vorname, h.Hausname, b.Woche
ORDER BY h.Hausname, b.Woche; 
SELECT    Hausname, Woche, Name 
FROM      Haus, Belegung, Kunde
WHERE     Haus.HausId = Belegung.HausId 
          AND Kunde.KundenId = Belegung.KundenId
ORDER BY  Hausname, Woche; 

Die Cypher-Abfrage ist nicht nur einiges weniger kompliziert und kürzer, sie ist auch viel intuitiver: Es sind keine abstrakten Joins notwendig.

Welche Häuser befinden sich auf Kreta ?

Sie wünschen eine Liste aller Häuser, welche auf der Insel Kreta liegen. Suchen Sie dafür Knoten raus, die das Label HAUS haben und inzident sind zu einer Kante vom Typ LAGE. Dieselbe Kante muss gleichermassen inzident sein mit einem Knoten, der das Label INSEL trägt. Weisen Sie dabei den Knoten passende Variablen zu.

Sie können anschliessend alle Häuser herausfiltern, welche nicht auf der Insel Kreta liegen. Vergleichen Sie zu diesem Zweck den Inselnamen mit dem String “Kreta”.

Geben Sie schliesslich die Häuser als Knotenmenge, als Graph oder als Tabelle aus.

MATCH (h:HAUS)-[:LAGE]-(i:INSEL) WHERE i.Inselname = "Kreta" RETURN h; 
MATCH (h:HAUS)-[:LAGE]-(i:INSEL) WHERE i.Inselname = "Kreta" RETURN h, i; 
MATCH (h:HAUS)-[:LAGE]-(i:INSEL) WHERE i.Inselname = "Kreta" RETURN DISTINCT h.Hausname; 

Auch hier lässt sich wieder ein klarer Unterschied erkennen, was die Komplexität angeht, wenn man die Cypher-Abfrage mit der SQL-Abfrage vergleicht:

Cypher-Abfrage SQL-Abfrage
MATCH (h:HAUS)-[:LAGE]-(i:INSEL)
WHERE i.Inselname = "Kreta" 
RETURN h.Hausname; 
SELECT Hausname FROM Haus
WHERE InselId = (SELECT InselId
                 FROM Insel
                 WHERE Inselname = 'Kreta'); 

In Cypher braucht man keine Verschachtlung vorzunehmen. Es reicht, eine zusätzliche Einschränkung für den Inselnamen festzulegen.

Schritt 9: Komplexere Abfragen erfassen

Häuser, die frei sind in Wochen 31 bis 33

Manchmal reicht ein einfacher Abgleich nicht, um die Knotenmenge so einzuschränken wie man es möchte. Neo4j erlaubt es deshalb mit sogenannten “collections” eine Knotenmenge in einer Variabel zwischenzuspeichern, um sie später zu referenzieren.

Interessieren Sie sich beispielsweise für Häuser, die in den Wochen 31 bis 33 frei sind, können Sie eine collection von Häusern definieren, welche in diesen Wochen besetzt sind, um in einem zweiten Durchgang alle Häuser auszuwählen, welche nicht in dieser collection sind.

Bei der Wochenangabe handelt es sich um einen ganzen Bereich. Um diesen einzuschränken haben Sie verschiedene Möglichkeiten: Sie können mit mehreren Vergleichen einen oberen und unteren Grenzwert festlegen oder Sie definieren mit der Funktion range() einen Bereich. Beide Varianten sind unten abgedruckt.

Variante mit mehreren Vergleichen :

MATCH (h1:HAUS)­-[b:BELEGUNG]-­()
WHERE b.Woche >= 31 AND b.Woche <= 33
WITH collect(DISTINCT h1.Hausname) AS besetzt 
MATCH (h2:HAUS)
WHERE NOT h2.Hausname IN besetzt 
RETURN h2.Hausname AS Hausname; 

Variante mit range() :

MATCH (h1:HAUS)­-[b:BELEGUNG]­-()
WHERE b.Woche IN range(31,33)
WITH collect(DISTINCT h1.Hausname) AS besetzt 
MATCH (h2:HAUS)
WHERE NOT h2.Hausname IN besetzt 
RETURN h2.Hausname AS Hausname; 

Welche Personen haben dasselbe Haus gemietet ?

Sie wünschen sich eine Liste von Personen, welche dasselbe Haus gemietet haben und den Namen des Hauses.

Mit folgender Abfrage können Sie eine solche Liste ausgeben. Obwohl Resultate herausgefiltert werden, bei denen k1 und k2 die selbe Person ist, sind dennoch Duplikate vorhanden. Neo4j erkennt nicht, dass das Paar k1=Aeby; k2=Zumsteg dasselbe ist wie k1=Zumsteg; k2=Aeby.

MATCH (k1:KUNDE)­-[:BELEGUNG]­-(h:HAUS)­-[:BELEGUNG]­-(k2:KUNDE) 
WHERE NOT k1 = k2
RETURN DISTINCT k1.Name, k2.Name, h.Hausname; 

Sie können dieses Problem umgehen, indem Sie die Bedingung NOT k1=k2 durch k1.KundenId<k2.KundenId ersetzen. So filtern Sie alle Resultate heraus, bei denen die KundenId von k1 grösser ist als die von k2 und erhalten die gewünschte Tabelle.

MATCH (k1:KUNDE)­-[:BELEGUNG]­-(h:HAUS)­-[:BELEGUNG]­-(k2:KUNDE)
WHERE k1.KundenId < k2.KundenId
RETURN DISTINCT k1.Name, k2.Name, h.Hausname; 

Welche Häuser hat Gessner bisher gebucht ?

Stellen Sie eine Liste aller Inseln zusammen, auf welchen der Kunde Gessner bisher ein Haus gebucht hat.

Eine Verbindung über eine undefinierte Anzahl Knoten und Kanten kann mit dem Muster ()­ – [*]­ – () ausgedrückt werden. Es ist also verlockend eine einfache Abfrage wie die folgende zu formulieren, welche in diesem Fall das richtige Resultat liefert: Eine Liste, welche nur die Insel Kreta enthält.

MATCH (k:KUNDE {Name:"Gessner"})­-[*]-­(i:INSEL)
RETURN DISTINCT i.Inselname; 

Die Abfrage ist jedoch falsch. Das Muster trifft auf alle Inseln zu, welche sich in dieser verbundenen Komponente des Graphen befinden. Die Abfrage sollte eher wie folgt lauten:

MATCH (k:KUNDE {Name:"Gessner"})­­--(:HAUS)­­--(i:INSEL)
RETURN DISTINCT i.Inselname; 

So können Sie sicherstellen, dass Gessner auch wirklich ein Haus auf dieser Insel gebucht hatte.

Bemerkenswert ist hier, dass trotz der zusätzlichen Einschränkung die Cypher-Abfrage sehr kompakt bleibt. Würde man eine analoge Abfrage in SQL formulieren, bräuchte es einen dreifachen Join über vier verschiedene Tabellen.

Welches Haus könnte man Wyss empfehlen ?

Sie würden dem Kunden Wyss gerne Häuser empfehlen, welche bis zu EUR 100 teurer sind als das teuerste Haus, welches er bisher gebucht hatte.

Mit folgender Abfrage können Sie eine Liste von Häusern in diesem Bereich, inkl. ihren Mietpreisen, ausgeben. Häuser die der Kunde schon einmal gebucht hat werden nicht berücksichtigt.

MATCH (k:KUNDE {Name:"Wyss"})­­--(h1:HAUS)
WITH max(h1.Miete) + 100 AS max_price, h1 AS h1 
MATCH (h2:HAUS)
WHERE NOT h1 = h2 AND h2.Miete <= max_price 
RETURN h2.Hausname, h2.Miete; 
Designed & Developed by Minh Tue NGUYEN