Aufbau einer Graphdatenbank mit Neo4j 2.0

Wunderbare Welt der Graphen
Kommentare

Weder relationale Datenbanken noch andere NoSQL-Lösungen sind für das Management verknüpfter Daten so gut geeignet wie Graphdatenbanken. Denn diese bilden Beziehungen zwischen Elementen effektiver ab und erlauben eine effiziente und performante Datenabfrage. Mit dem quelloffenen Neo4j lässt sich so eine breite Palette von Retail-Daten speichern und abfragen.

Mit zunehmender Reife der NoSQL-Landschaft haben sich vier Kategorien von Datenbanken herausgeschält. Drei davon (Key-Value-, spaltenorientierte und dokumentenorientierte Datenbanken) eignen sich zur Verarbeitung einfacher, strukturierter Datenelemente. Sie speichern und indizieren Datensätze, die keine oder lose Beziehungen zueinander aufweisen, und kommen ohne die von relationalen Datenbanken bekannten JOIN-Operationen aus. Dafür sind sie horizontal leicht skalierbar und können große Datenmengen schnell lesen und schreiben. Das vierte Mitglied der NoSQL-Familie, die Graphdatenbank, bewältigt auch die anspruchsvolle Aufgabe, stark vernetzte bzw. verknüpfte Daten effizient abzufragen. Graphdatenbanken eignen sich daher perfekt für die wirklichkeitsgetreue Modellierung und hochperformante Abfrage komplexer Echtweltdomains. Im Folgenden wird am Beispiel der verbreiteten Graphdatenbank Neo4j aufgezeigt, wie sich vernetzte Daten mithilfe von Graphen mit wenig Aufwand und hohem Gewinn speichern und abfragen lassen.

Was ist Neo4j?

Neo4j ist eine quelloffene ACID-transaktionale Graphdatenbank der Enterprise-Klasse. Seit ihrer Einführung 2003 ist sie zum Weltmarktführer im Bereich Graphdatenbanken avanciert – mit einer vitalen Community, aktiver Entwicklungsarbeit und zahlreichen Produktionsinstallationen. Graphdatenbanken ähneln relationalen Datenbanken oberflächlich. Sie bilden aber die Beziehungen zwischen Elementen viel effektiver ab. Damit können die bekannten Probleme beim Abfragen verknüpfter Daten umgangen werden. Im NoSQL-Bereich haben Graphdatenbanken mit diesem Datenmodell ebenso ein Alleinstellungsmerkmal.Neo4j speichert Daten in Knoten, die beliebige Attribute (Schlüssel-Wert-Paare) enthalten. Die Knoten wiederum sind über benannte, gerichtete Beziehungen (Relationen) miteinander verbunden. Die einzelnen Knoten können über eine Vielzahl dieser Beziehungen verknüpft sein, von denen jede benannt und gerichtet ist. Auf diese Weise entstehen aussagekräftige Datenmodelle, bei denen das semantische Beziehungsgeflecht zwischen den Einheiten ebenso wichtig ist wie die Einheiten selbst. Ein einfaches Beispiel für dieses auch als Property-Graph bezeichnete Datenmodell ist in Abbildung 1 dargestellt.

Abb. 1: Das Property-Graph-Datenmodell

Der Property-Graph aus Abbildung 1 zeigt einen kleinen, aber typischen Teilgraphen, bei dem die für die einzelnen Einheiten stehenden Knoten über Beziehungen miteinander verknüpft sind, die wiederum das semantische Wissen über die betreffenden Einheiten darstellen. Im obigen Beispiel mag Alice ihren Freund Bob, während Bob sowohl Alice als auch Cookies mag. Leider wird nicht jede Liebe erwidert. Gerichtete Graphen können auch diesen Fall abbilden, in dem Alice zwar Bob liebt, er jedoch nicht sie, d. h. die Beziehung zwischen den Einheiten nur in eine Richtung verläuft. Graphdatenbanken erlauben die Navigation jeder Beziehung in beide Richtungen. So kann ohne zusätzlichen Aufwand auch gefragt werden: „Wen liebt Alice?“ oder „Wer liebt Alice?“.
Property-Graphen sind bereits seit einigen Jahren erfolgreich im Einsatz, aber derzeit läuft der Innovationsmotor in der Graphtechnologie auf Hochtouren. Mit der Einführung von Knotenbezeichnern (Labels) in der Version 2.0 hat Neo4j das klassische Property-Graph-Modell um ein interessantes Feature erweitert: Anhand der Labels können Knoten mit Rollen versehen werden, sodass ähnliche Knotentypen wie z. B. „Kunde“ oder „Produkt“ gegenüber der Datenbank kenntlich gemacht werden. Abfragen werden durch diese zusätzlichen Informationen sowohl einfacher als auch schneller. Mit den neuen Knotenlabels lassen sich zudem – abgestimmt auf die jeweilige Domain – Uniqueness Constraints und automatische Indizierungen durchführen, was die Performance steigert. Das Beispiel in Abbildung 2 zeigt Knoten, die mit derartigen Bezeichnern versehen sind. Dabei wird sofort deutlich, dass Alice und Bob die einzigen Personen sind, die sich lieben. Bobs andere große Liebe – Cookies – gilt dagegen nur einem Produkt und ist somit kein Rivale für Alice.

Abb. 2: Labels erweitern das Property-Graph-Modell um Taxonomien für Knoten

Die beiden hier beschriebenen Beispiele zeigen, wie „Whiteboard-freundlich“ das Property-Graph-Modell ist – in Abwandlung des berühmten Akronyms könnte man auch sagen: „What You Draw Is What You Store“. Die Repräsentation in der Datenbank entspricht direkt dem konzeptuellen Modell. Dieses Modell erlaubt auch für „Problem“-Domains mit zahlreichen Anomalien, wie sie in der Realität häufig vorkommen, eine Verarbeitung ohne Daten-Denormalisierung. Um dies zu veranschaulichen, wollen wir uns nun direkt Neo4j zuwenden.

Neo4j: Höchste Effizienz durch native Unterstützung von Graphelementen

Die extrem hohe Leistungsfähigkeit verdankt Neo4j der so genannten indexfreien Adjazenz. Dies bedeutet nichts anderes, als dass die Beziehungsnavigation im Graphen nicht durch umfangreiche globale Indizes erfolgt, sondern dass jeder Knoten als „Mini-Index“ agiert: Seine Querverbindungen werden in Form einer Liste direkter Verweise zu seinen Nachbarknoten abgespeichert.
Dank der indexfreien Adjazenz ist Neo4j in der Lage, die nächsten Datensätze einer Abfrage äußerst ressourcenschonend zu verarbeiten. Die „Kosten“ (d. h. der Ressourcenbedarf bzw. die Komplexität) der Navigation ist O(1) (d. h. die Laufzeit ist konstant), während bei einem globalen Index diese Kosten im schlechtesten Fall O(log n) betragen. Bei einer Abfrage sind diese Kosten daher O(n), wobei n die Anzahl der in einer Graphdatenbank traversierten (d. h. durchsuchten) Knoten ist. Bei anderen Datenbanken, die globale Indizes zur Erfassung der Graphstruktur verwenden, betragen sie O(n log n). Diese Eigenschaft in Verbindung mit seinem hochperformanten Graphen-Cache- und angepassten Speicherlayout macht die Abfrage von Graphdaten mit Neo4j schnell und effizient.
Weder relationale Datenbanken noch andere NoSQL-Lösungen unterstützen die indexfreie Adjazenz direkt und sind daher für das Management verknüpfter Daten in der Regel wenig geeignet. Relationale Datenbanken leiden bei der Emulierung von Pfadabfragen unter kostspieligen JOIN-Operationen, während die Verarbeitung von denormalisierten Daten von Key-Value-, dokumentenorientieren- und spaltenorientierten Datenbanken eine spezielle Kodierung und Indizierung erfordert. Selbst dann liegt die Traversierungsgeschwindigkeit dieser Datenbankkategorien um Größenordnungen unter derjenigen nativer Graphdatenbanken.

Erste Schritte: Herunterladen von Neo4j 2.0

Zuerst muss die Datenbank heruntergeladen und installiert werden. Ausführliche Anweisungen zu Download, Installation und Ausführung von Neo4j auf Linux-, Mac- und Windows-Systemen sind unter http://www.neo4j.org/download zu finden. Einzige Voraussetzung hierfür ist Java 7. Nach der Installation kann die Graphdatenbank mit Daten gefüllt und abgefragt werden. Zunächst soll jedoch die Domäne definiert werden.

Aufmacherbild: Fantastic field at the dramatic overcast sky. Dark ominous clouds. Ukraine, Europe. Beauty world. von Shutterstock / Urheberrecht: Creative Travel Projects

[ header = Seite 2: Ermitteln von Produktempfehlungen mit Neo4j ]

Ermitteln von Produktempfehlungen mit Neo4j

Nach der allgemeinen Beschreibung von Property-Graphen werden wir uns nun mit einer Beispieldomain aus dem Retail-Sektor befassen. Diese ist leicht zu verstehen und zudem ein Anwendungsfall, der in der Praxis – insbesondere zur Ermittlung von Produktempfehlungen – sehr häufig vorkommt.
Zunächst muss eine grundlegende Frage beantwortet werden: Wie lässt sich ein einzelner Kunde mit seiner Einkaufshistorie modellieren? Das hier verwendete Szenario zeigt sehr anschaulich die Funktionsweise der Graphmodellierung, da es die drei Dimensionen Zeit, Kunde und Produkt beinhaltet. Diese Dimensionen lassen sich nahtlos als Graph modellieren. Bei der späteren Abfrage können dann einzelne oder alle Dimensionen einbezogen werden.

Abb. 3: Darstellung der Einkaufshistorie eines Kunden

Das Diagramm aus Abbildung 3 zeigt, wie aus einer einfachen verlinkten Liste von Warenkörben, die durch NEXT-Beziehungen miteinander verbunden sind, die Einkaufshistorie eines Kunden entsteht. Der Graph macht deutlich, dass der Kunde die Website drei Mal besucht hat. Den ersten Warenkorb hat er gespeichert (kenntlich gemacht durch die SAVED-Beziehung zwischen dem Knoten „Customer“ und „Basket“). Einen weiteren Warenkorb hat er tatsächlich gekauft, wie die Beziehung BOUGHT zwischen „Customer“ und „Basket“ zeigt, und aktuell füllt er einen dritten Warenkorb, wie aus der Beziehung CURRENT hervorgeht, die auf einen aktiven Warenkorb am Anfang der verlinkten Liste verweist. Dabei sollte klar sein, dass es sich hier nicht um ein Schema oder ein Entity-Relationship-Diagramm handelt, sondern um die Darstellung der tatsächlichen Daten für einen konkreten Kunden. Ein in der Realität vorkommender Graph für viele solcher Kunden hätte naturgemäß gewaltige Ausmaße, die den Rahmen eines Artikels sprengen würden; die Struktur wäre jedoch grundsätzlich identisch.
In der Darstellung als Graph lässt sich das Kundenverhalten problemlos nachvollziehen: Bei seinem ersten Besuch als potenzieller Neukunde brach er den Kauf von Zahnpasta zunächst ab, kam aber einen Tag später wieder und kaufte dann sowohl Zahnpasta als auch Brot und Butter. Bei seinem nächsten Einkauf landete erneut Brot und Butter im Warenkorb. Anhand des so ersichtlichen Einkaufsmusters könnte der Händler diesen Kunden künftig individueller betreuen.
Nachdem nun klar ist, wie ein einfaches Graphmodell funktioniert, soll es in Neo4j übertragen werden. Die Datenverarbeitung in Neo4j 2.0 erfolgt primär über die Abfragesprache Cypher, mit der Graphen abgefragt, geändert, mit Labels versehen und indiziert werden können. Obwohl es auch interne Java-APIs gibt (mit denen beliebige Graphalgorithmen ausgedrückt werden können), ist Cypher häufig die bessere Wahl und zudem definitiv der beste Ausgangspunkt, um die Grundlagen der Graphabfrage zu erläutern. In einem ersten Schritt muss der Kundengraph über Cypher in Neo4j geladen werden, wie Listing 1 zeigt.

CREATE (alice:Customer {name: 'Alice'})


CREATE (b1:Basket {id: 'a332deb', date: 20130928})     
CREATE (b1)-[:NEXT]->(b2:Basket {id: 'a332deb', date: 20130929})     
CREATE (b2)-[:NEXT]-> (b3:Basket {id: 'ffda309', date: 20131010})

CREATE (alice)-[:SAVED]->(b1)     
CREATE (alice)-[:BOUGHT]->(b2)     
CREATE (alice)-[:CURRENT]->(b3) 

CREATE (toothpaste)-[:IN]->(b1)     
CREATE (toothpaste)-[:IN]->(b2)     
CREATE (bread)-[:IN]->(b2)     
CREATE (butter)-[:IN]->(b2)     
CREATE (bread)-[:IN]->(b3)     
CREATE (butter)-[:IN]->(b3)

Normalerweise werden die Cypher-Statements wie in Listing 1 von einer Anwendung erzeugt; zu Lernzwecken ist der Prozess hier jedoch in der Langform dargestellt. Cypher stellt die Speicherstrukturen und die Mustersuche als ASCII-Art dar. Dabei werden Knoten durch Klammern eingeschlossen (node) und Beziehungen durch Pfeile wie z. B. –[:LOVES]-> symbolisiert, während für die Eigenschaften von Knoten oder Beziehungen eine an JSON orientierte Syntax wie { name: ’Alice’, age : 33} verwendet wird.
Zur Erzeugung eines Kunden wird die Syntax CREATE (alice:Customer {name: ‚Alice‘}) verwendet. Sie erstellt einen Knoten mit dem Label Customer und weist ihm eine Eigenschaft zu, deren Schlüssel name und deren Wert Alice ist. Danach führt sie einen Identifikator alice für die aktuelle Abfrage ein. Mithilfe dieses Identifikators werden die Beziehungen zu anderen, auf die gleiche Art und Weise erzeugten, Knoten hergestellt. So erzeugt CREATE (alice)-[:BOUGHT]->(b2) z. B. eine ausgehende Beziehung BOUGHT, die von dem für Alice stehenden Knoten auf den als b2 bezeichneten Warenkorbknoten zielt. Obwohl jedes Statement für sich genommen relativ einfach ist, können durch Aggregation damit sehr schnell komplexe und umfangreiche Graphstrukturen geschaffen werden.
Nachdem ein Graph des Kunden und der von ihm erworbenen Produkte vorliegt, besteht der nächste Schritt darin, anhand von Empfehlungen sein künftiges Kaufverhalten zu beeinflussen. Die einfachste Empfehlung bestünde darin, ihm die beliebtesten Produkte des Filialsortiments zu zeigen. Wie einfach dies in Cypher ist, zeigt Listing 2, das eine Abfrage der fünf beliebtesten Produkte zeigt.

MATCH (customer:Customer)-[:BOUGHT]->()<-[:IN]-(product:Product)
RETURN product, count(product) AS freq
ORDER BY freq DESC LIMIT 5

Anhand der Abfrage in Listing 2 lässt sich einiges über Cypher erfahren. Zunächst werden mit der MATCH-Klausel – erneut unter Verwendung von ASCII-Art – die relevanten Graphmuster deklariert. Gelesen werden kann sie als „Kunden, die einen Warenkorb mit einem Produkt gekauft haben“, wobei „Warenkorb“ durch den anonymen Knoten () ersetzt wurde, da der konkrete Warenkorb für die Abfrage nicht weiter von Belang ist. Im Anschluss daran liefert RETURN die dem Muster entsprechenden Ergebnisse, auf die wir dann bekannte Aggregatsfunktionen (count, sum, collect) anwenden können. Konkret erhalten wir den Knoten, der das Produkt repräsentiert und die Anzahl der Verkäufe (Pfad zwischen Kunde und Produkt). Wir ordnen dann die zurückgegebenen Knoten in absteigender Reihenfolge, wobei wir uns auf die fünf höchsten Ergebnisse beschränken, um die fünf beliebtesten Produkte des Sortiments zu erhalten, wie in Listing 3 gezeigt wird.

+--------------------------------------------------------------+ 
| product                                     | count(product) | 
+--------------------------------------------------------------+ | Node[69]{sku:11122398,desc:"whole milk"} | 5 | | Node[68]{sku:75620009,desc:"unsliced loaf"} | 4 | | Node[70]{sku:32986438,desc:"tagliatelle"} | 3 | | Node[66]{sku:95645311,desc:"butter"} | 3 | | Node[71]{sku:32405923,desc:"tea bags"} | 2 |
+--------------------------------------------------------------+

Die Abfrage in Listing 2 ist jedoch noch nicht perfekt. Erstens beschränkt sie sich nicht auf einen Kunden, sondern betrachtet alle Kunden des Händlers. Somit erlaubt sie keine präzise Aussage zu einer konkreten Person, obwohl sie für das Supply Chain Management dennoch von Nutzen sein könnte. Da sie zweitens das Kaufverhalten aller Kunden durchsucht, liegt ihre Antwortzeit vermutlich über dem Millisekundenbereich, der zwischen einer Nutzeranfrage in einer Webanwendung und deren Antwort verstreichen darf.
Auch hier lässt sich mit Cypher problemlos Abhilfe schaffen. Eine fast ebenso einfache Empfehlung wie die obige könnte darin bestehen, diejenigen Produkte zu ermitteln, die der Kunde in der Vergangenheit bevorzugt gekauft hat (Listing 4).

MATCH (customer:Customer)-[:BOUGHT]->()<-[:IN]-(product:Product)
WHERE customer.name='Alice'
RETURN product, count(product) ORDER BY count(product) DESC

Der einzige Unterschied zwischen Listing 4 und Listing 2 besteht in der Aufnahme der WHERE-Klausel, die besagt, dass nur ein Kunde mit dem Namen Alice dem gesuchten Muster entspricht. Eine derartige Abfrage ist nicht nur für den Kunden sinnvoller, sondern sie ist auch schneller, da die Datenbank durch Ausschluss eines Großteils des Graphen (d. h. aller Teile, in denen Alice nicht vorkommt) sehr viel weniger Daten zu verarbeiten hat.
Im Zeitalter des Social Selling wäre natürlich noch besser, wenn wir dem Kunden populäre Produkte in seinem sozialen Netzwerk aufzeigen könnten, anstelle uns auf seine eigenen Einkäufe zu beschränken. Schließlich ist bekannt, welch enormen Einfluss soziale Medien auf das Kaufverhalten haben. Wie nicht anders zu erwarten, lässt sich Neo4j problemlos um eine soziale Dimension erweitern. Hierfür werden in Listing 5 (Anlegen von Freunden als soziales Netzwerk des Kunden) ganz einfach entsprechende Beziehungen hinzugefügt, die dann in Listing 6 (Cypher-Abfrage nach beliebten Produkten, die von Freunden ersten und zweiten Grades gekauft wurden) abgefragt werden, wodurch wir in Listing 7 sehr viel relevantere Ergebnisse erhalten.

CREATE (alice)-[:FRIEND]->(bob) CREATE (alice)-[:FRIEND]->(dora)
CREATE (bob)-[:FRIEND]->(alice) CREATE (bob)-[:FRIEND]->(dora)
CREATE (charlie)-[:FRIEND]->(dora)
CREATE (dora)-[:FRIEND]->(alice) CREATE (dora)-[:FRIEND]->(bob) CREATE (dora)-
  [:FRIEND]->(charlie)
MATCH (customer:Customer)-[:FRIEND*1..2]->(friend:Customer)
WHERE customer.name='Alice' AND customer <> friend
WITH DISTINCT friend
MATCH (friend)-[:BOUGHT]->()<-[:IN]-(product:Product)
RETURN product, count(product) AS freq
ORDER BY freq DESC LIMIT 5

Um die von direkten und indirekten Freunden gekauften Produkte abzurufen, wird die Abfrage aus Listing 6 in zwei logische Hälften geteilt. In der ersten Hälfte der Abfrage wird der Graph durchlaufen, um einen bestimmten Kunden (Alice) zu suchen und die Beziehung zu dessen Freunden und den Freunden dieser Freunde aufzudecken. In der zweiten Hälfte wird dann die Einkaufsstatistik über deren Warenkörbe ermittelt. Die Ermittlung des Freundesnetzwerks ist nicht weiter kompliziert, da Neo4j Pfadrepräsentationen mit variabler Länge zulässt, z. B. um eine Beziehung der Tiefe 1 oder 2 zwischen einem Kunden und seinen Freunden wie im Fall von -[:FRIEND*1..2]-> auszugeben. In unserem Beispiel erhalten wir alle direkten Freunde (Beziehung der Tiefe 1) und sekundären Freunde (Beziehung der Tiefe 2); die Notation kann jedoch für eine beliebige Höchst- oder Mindesttiefe parametrisiert werden.
Da Alice auch im zweiten Grad als Freundin von Freunden wieder auftauchen kann, muss sie selbst dann noch herausgefiltert werden. Hier kommt die zweite WHERE-Zeile ins Spiel. Sie legt fest, dass nur dann ein Match festgestellt wird, wenn Kunde und Freund nicht derselbe Knoten sind.
Auch Doppelnennungen in Form von indirekten Freunden, die auch direkte Freunde sind (oder umgekehrt) bzw. Dopplungen aus dem sekundären Netzwerk, sind unerwünscht. Dies kann passieren, weil Bob sowohl ein direkter Freund als auch – über Dora – ein indirekter Freund von Alice ist. Mit dem Schlüsselwort DISTINCT wird sichergestellt, dass passende Muster nicht dupliziert zurückgegeben werden.
Nachdem die Mitglieder des Freundesnetzwerks ermittelt wurden, führt die WITH-Anweisung von der ersten in die zweite Hälfte der Abfrage. WITH arbeitet dabei genauso wie RETURN, sodass Aggregation (count(friend)), Projektion (customer.name), Sortierung und Paginierung (LIMIT, SKIP) auch mitten in der Abfrage erfolgen kann. Wichtig ist das auch für Änderung der weitergenutzten Menge (Kardinalität) an Informationen, damit folgende Abfrageteile nicht unnütz mit zu vielen oder duplikaten Ausgangsdaten arbeiten müssen.
Dort befinden wir uns wieder auf vertrautem Terrain, d. h. die Abfrage sucht nach Kunden (den gerade ermittelten Personen aus dem Netzwerk), die Produkte gekauft haben, und sortiert sie nach der Anzahl ihrer Einkäufe (der Warenkörbe, in denen die einzelnen Produkte enthalten waren). Dabei zeigt sich, dass Vollmilch in dieser Gruppe das beliebteste Produkt ist (Listing 7). Da Alice noch keine Vollmilch gekauft hat, sollte sie das eventuell nachholen, um sie im Haus zu haben, falls einer ihrer Freunde sie besucht.

+---------------------------------------------------------------+
| product                                      | count(product) |
+---------------------------------------------------------------+
| Node[155]{sku:11122398,desc:"whole milk"}    | 5              |
| Node[154]{sku:75620009,desc:"unsliced loaf"} | 4              |
| Node[156]{sku:32986438,desc:"tagliatelle"}   | 3              |
| Node[157]{sku:32405923,desc:"tea bags"}      | 2              |
| Node[152]{sku:95645311,desc:"butter"}        | 1              |
+---------------------------------------------------------------+

An dieser Stelle lässt sich leicht erkennen, wie die Abfrage um weitere Dimensionen ergänzt werden kann, z. B. um Geoinformationen zur Kundenadresse, um demographische Daten, um Informationen zu Produktlieferungen und Lagerbestand und vieles mehr. Diese nahtlose Einfügung mehrdimensionaler Daten ist der große Vorteil einer Modellierung mit Property-Graphen. Der große Vorteil von Neo4j besteht darin, dass es die Arbeit mit Property-Graphen so einfach (dank Cypher), schnell (dank der indexfreien Adjazenz) und zuverlässig (dank ACID-Transaktionen und Hochverfügbarkeits-Clustering) macht.

Fazit

Auf den vorangegangenen Seiten wurde gezeigt, wie wir mit Neo4j und seiner Abfragesprache Cypher eine breite Palette von Retail-Daten vom Produktsortiment bis hin zu Kundeneinkäufen speichern und abfragen können. Dabei wurde ebenfalls deutlich, wie einfach es ist, wertvolle Erkenntnisse aus diesen Daten zu gewinnen – obwohl es sich um eine komplex strukturierte Domäne handelt.
Neo4j ermöglicht die einfache Nutzung von Graphen, um Daten aus Onlinesystemen annähernd in Echtzeit zu analysieren und wird von etablierten Unternehmen und Start-ups gleichermaßen erfolgreich eingesetzt. Falls Sie Neo4j 2.0 näher kennenlernen wollen, werfen Sie einen Blick auf die verfügbaren Previews. Die neue Version 2.0 wurde vor Kurzem veröffentlicht. Wenn Sie sich näher mit Neo4j, Cypher und der Welt der Graphen vertraut machen wollen, empfehlen wir Ihnen das kürzlich bei entwickler.press erschienene Fachbuch „Neo4j 2.0 – eine Graphdatenbank für alle“ (siehe gleichnamiger Kasten) von Michael Hunger oder den Onlinekurs „Getting Started with Neo4j“, den Sie unter http://neo4j.org/learn/online_course abrufen können.

e.press: Neo4j 2.0Der Mehrwert von Informationen steckt nicht notwendigerweise in der reinen Menge von Daten, sondern vor allem in den Beziehungen zwischen Elementen. Bisher war es nicht so einfach, die interessanten, vernetzten Domänen verlustlos in einer Datenbank zu speichern und effizient abzufragen. Neo4j, besonders die neue Version 2.0, erlaubt es, komplexe Datenmodelle direkt zu modellieren und herausfordernde Anwendungsfälle performant umzusetzen. In seinem Buch gibt Michael Hunger, langjähriger Mitarbeiter von Neo Technology, an praktischen Beispielen einen Überblick zur Anwendung der quelloffenen Graphdatenbank.

 

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -