2017-01-04 3 views
1

Hallo Ich erhalte den folgenden Fehler beim Versuch, Knoten und Beziehungen zu erstellen/zusammenführen. Es passiert nicht immer, aber es kommt hin und wieder vor.CypherError beim Erstellen/Zusammenführen von Graphen mit Neo4j-Python Connector

CypherError: An unexpected failure occurred, see details in the database logs, reference number eaf50bff-deca-4055-9450-6a76c31534e4.

Dies ist die Traceback:

--------------------------------------------------------------------------- 
CypherError        Traceback (most recent call last) 
<ipython-input-21-9700f3a5d3fa> in <module>() 
     7  tx.success = True 
     8  #tx.close() 
----> 9 session.close() 

/databricks/python/local/lib/python2.7/site-packages/neo4j/v1/session.pyc in close(self) 
    522   """ 
    523   if self.last_result: 
--> 524    self.last_result.buffer() 
    525   if self.transaction: 
    526    self.transaction.close() 

/databricks/python/local/lib/python2.7/site-packages/neo4j/v1/session.pyc in buffer(self) 
    246   if self.connection and not self.connection.closed: 
    247    while not self._consumed: 
--> 248     self.connection.fetch() 
    249    self.connection = None 
    250 

für My Code erstellen/Merge ist dies:

for chunk in chunk_list: 
    with session.begin_transaction() as tx: 
    for record in chunk: 
     tx.run("MERGE (source:UID {userid : {m}, timestamp: {a}})" 
      "MERGE (target:UID {userid : {n}, timestamp: {a}})" 
      "MERGE (source)-[:HasConnection]-(target)", {"m": record.source, "n": record.target, "a": record.unix_timestamp_s}) 
    tx.success = True 
    #tx.close() 
    session.close() 

chunk_list eine Liste mit mehreren Listen von Datensätzen ist. Jede der Listen in chunk_list hat mehrere Zeilen (ca. 10000) und jede Zeile enthält drei Spalten, Quelle, Ziel und Zeitstempel.

Für jede Liste innerhalb von chunk_list öffnen wir eine Sitzung, führen die Zusammenführungsoperationen durch und schließen dann die Sitzung.

Das Problem beginnt, wenn der Graph mehr als 10 Millionen Knoten überschreitet. Sagen wir für Tag 1, dass die chunk_list 4 Millionen Zeilen hat, es würde gut funktionieren, für Tag 2, wenn die chunk_list 4 Millionen Zeilen hat, würde es auch gut funktionieren. Aber wenn am dritten Tag 3 Millionen Zeilen vorhanden sind und die Gesamtanzahl der Knoten im Neo4j-Diagramm mehr als 10 Millionen beträgt, dann beginnt das Problem.

+1

Da Sie zusammenführen: UID-Knoten mit beiden Benutzer-ID und Zeitstempel, bin ich richtig, dass die Kombination userid + timestamp der eindeutige Nachschlageschlüssel zu a: UID, dh es kann mehrere sein: UIDs mit der gleichen Benutzer-ID aber unterschiedlich Zeitstempel? Oder ist userid der eindeutige Suchschlüssel und Sie versuchen, die Zeitstempel zu aktualisieren und eine Verbindung zu erstellen? – InverseFalcon

+0

Es sollte dieselbe Benutzer-ID sein, aber der Zeitstempel ändert sich während der Zusammenführung. @InverseFalcon – sjishan

Antwort

0

Es geschah, weil die Datenbank aus Festplattenspeichern lief, die aufgezeichnet wurde im Protokoll.

1

Einer der Gründe, warum dies so lange dauert, ist, dass Ihre Abfrage nicht das tut, was Sie denken, dass es tut.

Eine MERGE zu machen, ist so, als würde man zuerst versuchen, ein MATCH zu machen, und wenn keine Übereinstimmungen gefunden werden, dann muss man CREATE machen.

In Ihrem Kommentar haben Sie gesagt, dass der Zeitstempel während der MERGE-Operation geändert werden sollte. Sie möchten also die Eigenschaften für Knoten mit derselben Benutzerkennung aktualisieren, aber das ist nicht das, was Ihre MERGE tut.

Ihre MERGE versucht zuerst, einen: UID-Knoten mit der angegebenen Benutzer-ID und dem angegebenen Zeitstempel abzugleichen, aber in Ihrem Diagramm wird kein solcher Knoten vorhanden sein, da der Zeitstempel neu ist ... wird es einen: UID-Knoten geben mit der gleichen Benutzerkennung, aber mit einem anderen Zeitstempel, so dass keine Übereinstimmung gefunden wird, und ein brandneuer UID-Knoten mit der gleichen Benutzerkennung wie ein bestehender Knoten und der neue Zeitstempel erstellt wird.

So wird Ihre MERGE immer neue Knoten erstellen und nie auf vorhandenen Knoten übereinstimmen. MERGE allein wird die Eigenschaftswerte niemals aktualisieren, also versuchen Sie niemals, es so zu verwenden.

Um ein Spiel durchführen und ein Update, müssen Sie nur auf den minimalen einzigartigen Eigenschaften basiert fusionieren auf einem vorhandenen Knoten entsprechen, und dann SET verwenden, um Eigenschaften zu aktualisieren, wie folgt aus:

for chunk in chunk_list: 
    with session.begin_transaction() as tx: 
    for record in chunk: 
     tx.run("MERGE (source:UID {userid : {m}})" 
      "SET source.timestamp = {a}" 
      "MERGE (target:UID {userid : {n}})" 
      "SET target.timestamp = {a}" 
      "MERGE (source)-[:HasConnection]-(target)", {"m": record.source, "n": record.target, "a": record.unix_timestamp_s}) 
    tx.success = True 
    #tx.close() 
    session.close() 

Zusätzlich Um sicherzustellen, dass Ihre MERGEs schnell sind, müssen Sie entweder einen Index oder eine eindeutige Einschränkung für: UID (Benutzer-ID) haben, ansonsten wird neo4j einen Label-Scan durchführen müssen, um die Knoten zu finden, was viel zu langsam für die Größe Ihrer ist Graph.

EDIT

Ich habe noch nicht Python mit Neo4j verwendet, aber ich bin diese Art von Schleife nicht sicher, die richtigen Mittel zur Verarbeitung mehrerer Datensätze ist, wie es aussieht wie es eine riesige humber von Kopien laufen des angegebenen Cypher-Segments. 5 Zeilen Cypher pro Zeile scheint extrem ... idealerweise sollten Sie Cypher-Code verwenden, um alle Zeilen gleichzeitig (oder zumindest die Zeilen pro Chunk) zu bearbeiten, wobei Ihre Eingabe zur Ausführung einfach in Zeilen konvertiert werden kann.

Ein besserer Ansatz könnte darin bestehen, eine Schleife zu verwenden, um eine Liste von Objekten (mit "m" - und "n" -Eigenschaften) zu generieren und die Liste und einen einzelnen Zeitstempel als Parameter an die Abfrage zu senden.

Sie können dann die Liste in Ihrem Cypher wieder in Zeilen abwickeln und diese verwenden. Also, wenn „Reihe“ war die Liste der Objekte Parameter, und „a“ Ihre Unix-Zeitstempel-Parameter blieb, das Cypher Segment würde wie folgt aussehen:

UNWIND {row} as line 
MERGE (source:UID {userid : line.m}) 
SET source.timestamp = {a} 
MERGE (target:UID {userid : line.n}) 
SET target.timestamp = {a} 
MERGE (source)-[:HasConnection]-(target) 
+0

Danke für die Korrektur und das Problem wurde auf Speicherplatz bezogen. – sjishan

+0

Bearbeitete meine Antwort, um darauf hinzuweisen, dass das gegebene Mittel, eine Schleife zum Erzeugen der Cypher-Transaktion zu verwenden, nicht das richtige Mittel ist, um sich diesem zu nähern. – InverseFalcon

Verwandte Themen