Daten Import via Groovy - 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 Groovy. Zunächst benötigen wir Groovy auf dem System. Danach wird gezeigt wie das Skript aussehen muss. Dieses Tutorial geht davon aus, dass Neo4j bereits installiert ist und Ubuntu eingesetzt wird. Ebenso verhält sich dies auch mit den 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 eurem Linux-System geladen.


Nun fangen wir mit dem eigentlichen Tutorial an.

Groovy installieren

Schaut zunächst ob ihr Groovy bereits installiert habt via groovy in der Konsole.

Sollte das nicht der Fall sein, dann also einfach apt-get install groovy. Im Anschluss nochmal kurz mit groovy checken.

Datenbank und Skript vorbereiten

Zuerst vergewissern wir uns, dass die Datenbank leer ist. Dazu einfach den graph.db Ordner löschen.

Als nächstes legen wir unter /home/scripts unsere Import-Datei Import_All.groovy an.

Groovy Skript

Jetzt benötigen wir nur noch den Groovy-Code, der den Import dann durchführen soll. Kopiert dazu folgenden Code in die Import_All.groovy Datei. Die wichtigen Stellen habe ich fett markiert. Im Grunde verhält sich dieser Code wie die LOAD CSV Befehle hintereinander, bloß automatisiert. Solltet ihr später einmal etwas testen wollen, so kommentiert einfach //if (lines > 1000) break; wieder ein wo ihr es braucht.

@Grab('com.xlson.groovycsv:groovycsv:1.0')
@Grab('org.neo4j:neo4j:2.1.4')
import static com.xlson.groovycsv.CsvParser.parseCsv
import org.neo4j.graphdb.*
enum Labels implements Label { Appln, Title, Person }
enum Types implements RelationshipType { HAS_TITLE, WROTE }
def toMap(line) { line.columns.inject([:]){ m,k,v -> m.put(k,line.values[v]);m } }
def config = [
"use_memory_mapped_buffers": "true",
"neostore.nodestore.db.mapped_memory": "2G",
"neostore.relationshipstore.db.mapped_memory": "8G",
"neostore.propertystore.db.mapped_memory": "2G",
"neostore.propertystore.db.strings.mapped_memory": "2G",
"neostore.propertystore.db.arrays.mapped_memory": "0M",
"cache_type": "none",
"dump_config": "true"
]
def NO_PROPS=[:]
 
// cache
def applns = [:]
def persons = [:]
count = 0
time = start = System.currentTimeMillis()
def trace(output) {
    if (output || ++ count % 1000000 == 0) {
        now = System.currentTimeMillis()
        println "$count rows ${(now-time)} ms"
        time = now
    }
}
 
store=args[0]
println "Importing data into ${store}"
 
batch = org.neo4j.unsafe.batchinsert.BatchInserters.inserter(store,config)
try {
    appln_file = new File("/home/data/IMPORT_Appln.csv")
    lines = 0
    csv = appln_file.newReader()
    for (line in parseCsv(csv)) {
        lines++
        //if (lines > 1000) break;
        appln = line.appln_id
        if (!applns[appln]) {
            applns[appln] = batch.createNode([
                    ID: (line.appln_id).toInteger(),
                    nr: line.appln_nr,
                    filingDate: line.appln_filing_date],Labels.Appln)
        }
        trace()
    }
    csv.close()
    println "Appln imported"
    
    title_file = new File("/home/data/IMPORT_Title.csv")
    lines = 0
    csv = title_file.newReader()
    for (line in parseCsv(csv)) {
        lines++
        //if (lines > 1000) break;
        title = batch.createNode([title:line.appln_title],Labels.Title)
        appln = line.appln_id
        if (applns[appln]) {
            batch.createRelationship(applns[appln], title, Types.HAS_TITLE, NO_PROPS)
        }
        trace()
    }
    csv.close()
    println "Title imported"
    
    person_file = new File("/home/data/IMPORT_Person.csv")
    lines = 0
    csv = person_file.newReader()
    for (line in parseCsv(csv)) {
        lines++
        //if (lines > 1000) break;
        person = line.person_id
        if (!persons[person]) {
            persons[person] = batch.createNode([
                    ID: (line.person_id).toInteger(),
                    name: line.person_name],Labels.Person)
        }
        trace()
    }
    csv.close()
    println "Person imported"
    
    per2app_file = new File("/home/data/IMPORT_Per2App.csv")
    lines = 0
    csv = per2app_file.newReader()
    for (line in parseCsv(csv)) {
        lines++
        //if (lines > 1000) break;
        person = line.person_id
        appln = line.appln_id
        if (applns[appln] && persons[person]) {
            batch.createRelationship(applns[appln], persons[person], Types.WROTE, NO_PROPS)
        }
        trace()
    }
    csv.close()
    println "Per2App imported"
    
    batch.createDeferredSchemaIndex(Labels.Appln).on("ID").create()
    println "Appln.ID index finished"
    batch.createDeferredSchemaIndex(Labels.Title).on("title").create()
    println "Title.title index finished"
    batch.createDeferredSchemaIndex(Labels.Person).on("ID").create()
    println "Person.ID index finished"
} finally {
    batch.shutdown()
    trace(true)
    println "Total $count Rows ${applns.size()} Authors took ${(now-start)/1000} seconds."
}

Nun gehen wir zurück in die Konsole und führen time groovy Import_All.groovy /var/lib/neo4j/data/graph.db aus. Achtet darauf im richtigen Ordner zu sein.

Neo4j Import testen

Nachdem die Daten erfolgreich importiert wurden, testen wir noch ob eine Query das Ergebnis zurückliefert was wir erwarten. Dazu mit /var/lib/neo4j/bin/neo4j start Neo4j starten.

Unsere Test-Query ist wieder MATCH (a:Appln)-[r]-(b) WHERE a.ID =26978 RETURN a,r,b und sie gibt korrekte Werte zurück. Also war mit dem Import offensichtlich alles ok.

Fazit

Groovy bietet ebenso wie LOAD CSV eine sehr einfache Möglichkeit auf die Schnelle Daten zu importieren. Groovy übertrifft den LOAD CSV in Sachen Importzeit bei weitem. Allerdings kommt es nicht an das native Java heran. Wer also maximalen Speed braucht ist mit Java besser aufgehoben. Allerdings wenn ihr nur wenige Daten habt, ist Groovy sehr praktisch.

Kommentar schreiben

Kommentare: 2
  • #1

    Heiko (Freitag, 07 November 2014 11:34)

    Hab grad das Tutorial durchgearbeitet. Hat alles geklappt auch mit meinem eigenen Datensatz. Wirklich sehr einfache Methode muss ich sagen. Und reicht von der Geschwindigkeit auch vollkommen aus.

    Vielen Dank.

  • #2

    kwoxer (Freitag, 07 November 2014 11:54)

    Das freut mich sehr. Ja eigentlich wollte ich auch noch ein Java Beispiel zeigen. Aber unter Linux bin ich noch nicht so in Sachen Maven und Java bewandert. Mal schauen ob ich das noch hinbekommen. Ich könnte zwar auch zeigen wie ich mein Eclipse Projekt auf den Server schiebe. Aber das ist finde ich ungeeignet für Leute, die nicht mit Eclipse arbeiten wollen. Schauen wir mal ;)

    LG