Daten Import via LOAD CSV - Neo4j Fallbeispiel Tutorial

Nachdem wir gesehen haben wie man Neo4j installiert und angefallene Daten wieder ganz einfach löschen kann, wollen wir jetzt schauen wie man Daten auf unterschiedlicher Weise importieren kann. Auch hier gibt es wieder mehrere Methoden. Wir wählen in diesem Tutorial den Weg über den LOAD CSV Befehl. Dieser vereinfacht das Importieren enorm und ist mit Abstand das Einsteiger-freundlichste Verfahren Daten zu importieren. Dieses Tutorial geht davon aus, dass Neo4j bereits installiert ist und ein Ubuntu eingesetzt wird. Ebenso verhält sich dies auch mit DigitalOcean Root-Zugriff, wo ihr letzten Endes ja auch Ubuntu als Untersatz wählen könnt.

Vorbereitungen

Damit ihr dieses Tutorial verstehen könnt, ist es notwendig einige Vorbereitungen zu treffen. Danach verfügt ihr dann über die Grundlagen des Schemas und habt bereits die Daten auf eurer Linux-System geladen.

Nun fangen wir mit dem eigentlichen Tutorial an.

Datenbank erneuern und Index definieren

Als erstes schalten wir Neo4j ab mit /var/lib/neo4j/bin/neo4j stop.  Danach löschen wir die bestehende Datenbank mit rm -r /var/lib/neo4j/data/graph.db/. Dies stellt sicher, dass wir folglich nun wirklich auf einer leeren Datenbank arbeiten. Da LOAD CSV einen laufenden Neo4j-Server voraussetzt, starten wir per /var/lib/neo4j/bin/neo4j start den Server und erzeugen somit eine frische Datenbank.

Anfangs sollten wir die Indizes setzen, damit wir zwischendurch keine Probleme kriegen wenn wir Realationen setzen. Dazu /var/lib/neo4j/bin/neo4j-shell in die Konsole. Und hier einfach die folgenden 4 Zeilen markieren, einfügen und abschicken. Am Ende nochmal Enter für die letzte Zeile nicht vergessen.

CREATE INDEX ON :Appln(ID);
CREATE INDEX ON :Title(applnID);
CREATE INDEX ON :Title(title);
CREATE INDEX ON :Person(ID);

Ihr solltet dann folgende Mitteilungen bekommen.

Indexes added: 1
2150 ms

Indexes added: 1
109 ms

Indexes added: 1
65 ms

Indexes added: 1
37 ms

LOAD CSV Skripte definieren

Im nächsten Schritt erstellen wir das Mapping. Hierbei werden unsere 4 Dateien in das Schema der Datenbank umgewandelt.

Wir erzeugen folglich die im Bild dargestellten 5 Skripte in /home/scripts.

Appln

Die Import_Appln.txt füllt ihr mit:

USING PERIODIC COMMIT 3000
LOAD CSV WITH HEADERS FROM "file:///home/data/IMPORT_Appln.csv" AS csvLine WITH csvLine
CREATE (:Appln {     ID: toInt(csvLine.appln_id),
                                  nr: csvLine.appln_nr,
                                  date: csvLine.appln_filing_date});

Title

Die Import_Title.txt füllt ihr mit:

USING PERIODIC COMMIT 5000
LOAD CSV WITH HEADERS FROM "file:///home/data/IMPORT_Title.csv" AS csvLine WITH csvLine
CREATE (:Title {     applnID:toInt(csvLine.appln_id),
                               title:csvLine.appln_title });

Die Import_Tit2App.txt füllt ihr mit:

USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM "file:///home/data/IMPORT_Title.csv" AS csvLine WITH csvLine
MATCH (appln:Appln),(title:Title)
WHERE appln.ID = toInt(csvLine.appln_id) AND title.applnID = toInt(csvLine.appln_id)
CREATE (appln)-[:HAS_TITLE]->(title);

Person

Die Import_Person.txt füllt ihr mit:

USING PERIODIC COMMIT 3000
LOAD CSV WITH HEADERS FROM "file:///home/data/IMPORT_Person.csv" AS csvLine WITH csvLine
CREATE (:Person {    ID: toInt(csvLine.person_id),
                                  name: csvLine.person_name});

Per2App

Die Import_Per2App.txt füllt ihr mit:

USING PERIODIC COMMIT 1000
LOAD CSV WITH HEADERS FROM "file:///home/data/IMPORT_Per2App.csv" AS csvLine WITH csvLine
MATCH (appln:Appln),(person:Person)
WHERE appln.ID = toInt(csvLine.appln_id) AND person.ID = toInt(csvLine.person_id)
CREATE (person)-[:WROTE]->(appln);

LOAD CSV Skripte ausführen

Nun da wir 5 Skripte definiert haben, fehlt es nur noch diese auszuführen. Diese werden jetzt mit Hilfe der Neo4j-Shell ausgeführt.

/var/lib/neo4j/bin/neo4j-shell -file ///home/scripts/Import_Appln.txt

Nodes created: 100000
Properties set: 300000
Labels added: 100000
67631 ms

/var/lib/neo4j/bin/neo4j-shell -file ///home/scripts/Import_Title.txt

Nodes created: 90000
Properties set: 180000
Labels added: 90000
43071 ms

/var/lib/neo4j/bin/neo4j-shell -file ///home/scripts/Import_Tit2App.txt

Relationships created: 90000
64634 ms

/var/lib/neo4j/bin/neo4j-shell -file ///home/scripts/Import_Person.txt

Nodes created: 50000
Properties set: 100000
Labels added: 50000
19192 ms

/var/lib/neo4j/bin/neo4j-shell -file ///home/scripts/Import_Per2App.txt

Relationships created: 50000
43150 ms

Test der importierten Daten

Wir wollen nun mit einer simplen Query testen ob die Daten zum einen korrekt importiert wurden und zum anderen die Beziehungen und Labels stimmen. Dazu habe ich eine Appln herausgesucht, welche von einer Person geschrieben wurde und einen Title hat. Wie ihr sehen könnt führen die Beziehungen in die richtige Richtung und auch die Daten der Knoten stimmen mit den Ausgangsdaten überein.

MATCH (a:Appln)-[r]-(b) WHERE a.ID =26978 RETURN a,r,b

Hintergründe zu LOAD CSV Einzelheiten

Hier möchte ich ganz kurz auf die wichtigen Details im Prozess eingehen, welche zum Verständnis noch fehlen könnten.

Warum steht vor der ID ein toInt?

Die toInt-Funktion ist wichtig, damit Neo4j weiß, dass es sich hier auch wirklich um eine Zahl handelt. Theoretisch könntest du diese auch als String lassen, aber das würde nur unnötig Ressourcen kosten.

Wieso sind deine Laufzeiten der Skripte so hoch?

Da liegt daran, weil das Linux-System per Windows-Hostsystem gestartet wurde. Quasi steht dem Skript nur 20% CPU des Systems zur Verfügung. Also normalerweise erzielt man natürlich viel bessere Werte.

Wie kann ich die Importzeit weiter optimieren?

Wie bereits erwähnt solltest du den USING PERIODIC COMMIT x "perfekten" Wert für x für dein System ermitteln. Diese hängt von Menge der durchschnittlichen Buchstaben der Zeilen ab. Das ist also sehr stochastisch und unterschiedlich. Am besten hier also einfach durchtesten mit jeweils 100.000 Zeilen. Ansonsten kann es nicht schaden das Neo4j System zu konfigurieren.

Warum verwendest du für die Title 2 Skripte?

Nun das hat den Hintergrund, dass LOAD CSV nicht in der Lage ist, in nur einem Skript Nodes zu erstellen und gleichzeitig Relationen zu erstellen. Bei wenigen Datenmengen mag dies ohne Fehler möglich sein, aber generell ist davon abzuraten, da oft sonst ein HEAP ERROR geworfen wird. Daher solltet ihr in solchen Fällen zwei einzelne Skripte verwenden.

Funktioniert LOAD CSV auch mit Millionen von Daten?

Der hier verwendete Datensatz ist mit ~300.000 Zeilen sehr klein. 300 Mio Zeilen sind keine Seltenheit in Sachen Big Data und der Import würde dort natürlich identisch sein. Einige Parameter sollten dann dabei verändert werden, aber dies hängt auch sehr stark mit dem System zusammen, von daher ist hier viel Austesten notwendig. Auch solltet ihr wissen, dass LOAD CSV immer langsamer ist, als wenn ihr direkt Java Code schreiben würdet. Von daher wenn ihr maximalen Speed braucht, greift zu reinem Java Code.

Wozu hast du beim Download einen externen Link angegeben?

Diese Links biete ich euch an, damit ihr selber zufällige Daten generieren oder zumindest etwas von meinen Daten abweichen könnt. Dies ist optional aber wie ich finde ein guter Weg auch das Skript einmal mit anderen Daten zu testen. Oft kann es vorkommen das einige Besonderheiten oder Fehler erst dann auftreten. Beachtet bitte, dass diese Webseite nur Dateien erstellen kann, die kleiner als 100.000 Zeilen sind.

Fazit

Der LOAD CSV Befehl bietet sehr viel Komfort beim Importieren von Daten in Neo4j. Man muss nur sehr wenige Stellen anpassen um läuffähige und schnelle Imports zu ermöglichen.

Kommentar schreiben

Kommentare: 3
  • #1

    Andreas (Montag, 20 Oktober 2014 21:35)

    Moin moin kwoxer, sehr gut rausgearbeitet. Auch wenn ich kein Interesse an Neo4j und Graphen im Generellen habe, hab ich nur einmal überflogen und muss sagen, dass das wirklich sehr gut strukturiert und herausgearbeitet ist. Die Infos, die vllt nicht so interessant sind, am Ende zusammen gefasst. Perfekt. Hoffentlich mal wieder was, was mich mehr interessiert. Aber ich denke, das hier wird den einen oder anderen sicher helfen. Also mach auf jede Fälle weiter so. LG Andreas

  • #2

    kwoxer (Montag, 20 Oktober 2014 21:41)

    So soll es doch sein. =) Jeder soll alles verstehen können und einsteigen in der Thema wenn er Lust hat. Ist doch nicht schlimm wenn dich das Thema nicht interessiert. Lieber ehrliche Meinungen hier darüber. Und vllt kommt ja bald wieder was für dich. Also bis demnächst mein Freund.

    LG
    kwoxer

  • #3

    Michael Hunger (Dienstag, 21 Oktober 2014 18:01)

    Hi Kwoxer,

    wirklich guter Artikel. Gutes Intro in das Modell und Erklärung des Imports.
    Ich hätte nur wahrscheinlich ein alternatives Modell genommen, das leichter zu verstehen ist für den Leser.

    Vielen Dank