2016-10-18 1 views
6

Ein Teil meines Diagramms ist mit einem riesigen Join zwischen zwei großen Sammlungen erstellt, und ich benutze es jedes Mal, wenn ich Dokumente zu einer Sammlung hinzufüge. Die Abfrage basiert auf einem older post.ArangoDB: Einfügen als Funktion der Abfrage anhand eines Beispiels

FOR fromItem IN fromCollection 
    FOR toItem IN toCollection 
     FILTER fromItem.fromAttributeValue == toItem.toAttributeValue 
     INSERT { _from: fromItem._id, _to: toItem._id, otherAttributes: {}} INTO edgeCollection 

Dies dauert etwa 55.000 Sekunden für meinen Datensatz. Ich würde absolut begrüßen, Vorschläge, um das schneller zu machen.

Aber ich habe zwei verwandten Themen:

  1. Ich brauche einen Upsert. Normalerweise wäre upsert in Ordnung, aber in diesem Fall, da ich keine Möglichkeit habe, den Schlüssel im Voraus zu kennen, würde es mir nicht helfen. Um den Schlüssel in den Vordergrund zu bringen, müsste ich anhand eines Beispiels den Schlüssel der ansonsten identischen vorhandenen Kante abfragen. Das scheint vernünftig zu sein, solange es meine Leistung nicht tötet, aber ich weiß nicht, wie ich in AQL meine Abfrage bedingt so gestalten soll, dass sie eine Kante einfügt, wenn die äquivalente Kante noch nicht existiert, aber nichts tut, wenn die äquivalente Kante existiert. Wie kann ich das machen?
  2. Ich muss dies jedes Mal ausführen, wenn Daten zu beiden Sammlungen hinzugefügt werden. Ich brauche eine Möglichkeit, dies nur mit den neuesten Daten auszuführen, so dass es nicht versucht, die gesamte Sammlung zu verbinden. Wie kann ich AQL schreiben, die es mir erlaubt nur den neu eingefügten Datensätzen beizutreten? Sie werden mit Arangoimp hinzugefügt und ich kann nicht garantieren, in welcher Reihenfolge sie aktualisiert werden. Daher kann ich die Kanten nicht gleichzeitig mit der Erstellung der Knoten erstellen. Wie kann ich nur den neuen Daten beitreten? Ich möchte nicht jedes Mal 55k Sekunden ausgeben, wenn ein Datensatz hinzugefügt wird.
+1

Ich habe Abfragen in anderen Datenbanken mit der gleichen Herausforderung, wie Sie die Größe des Datensatzes reduzieren, wenn Sie es neu verknüpfen. Die Lösung, die für mich funktionierte, besteht darin, ein Feld namens "linked = false" in den Kollektionen fromKollection und toCollection hinzuzufügen. –

+1

... Wenn Sie dann neue Dokumente in eine der beiden Sammlungen einfügen, setzen Sie 'linked' immer auf' false'. Wenn Sie die Dokumente verknüpfen, gehen Sie auch zurück und setzen "verlinkt" auf "wahr". Um es zu beschleunigen, sollten Sie auch einen Index auf "verlinkt" setzen. Sie werden feststellen, dass dies Ihre Verarbeitung erheblich beschleunigt, obwohl es beim ersten Mal noch langsam ist, da alles den Wert "linked = false" haben wird. –

+1

Sie könnten eine Foxx-App schreiben, um es für Sie zu tun, ich dokumentierte eine Beispiel-Foxx-App für die Frage eines anderen, sie ist [hier] verfügbar (http://stackoverflow.com/questions/39897954/arangodb-aql-recursive-graph- Traversal) auf StackOverflow. Es lohnt sich, sich etwas Zeit zu nehmen, um Foxx zu lernen, denn es kann schön und schnell sein und eine Funktion wie das, was Sie beschreiben, ist ein perfekter Anwendungsfall. Die Funktion benötigt nicht einmal irgendwelche Parameter, sie läuft nur und sie scannt nur diese Datensätze mit 'linked = false'. –

Antwort

8

Wenn Sie Ihre Abfrage ausführen als ohne Indizes geschrieben, dann wird es zwei verschachtelte vollständige Sammlung Scans zu tun, wie kann, indem man die Ausgabe von

db._explain(<your query here>);

, die zeigt, zu sehen ist so etwas wie:

1 SingletonNode    1 * ROOT 
    2 EnumerateCollectionNode  3  - FOR fromItem IN fromCollection /* full collection scan */ 
    3 EnumerateCollectionNode  9  - FOR toItem IN toCollection /* full collection scan */ 
    4 CalculationNode    9   - LET #3 = (fromItem.`fromAttributeValue` == toItem.`toAttributeValue`) /* simple expression */ /* collections used: fromItem : fromCollection, toItem : toCollection */ 
    5 FilterNode     9   - FILTER #3 
    ... 

Wenn Sie das tun

db.toCollection.ensureIndex({"type":"hash", fields ["toAttributeValue"], unique:false})` 

Dann wird es eine einzige vollständige Tabelle Sammlung Scan in fromCollection und für jedes gefundene Element gibt es eine Hash-Suche in der toCollection, die viel schneller sein wird. Alles wird in Chargen passieren, also sollte dies bereits die Situation verbessern. Die db._explain() wird dies zeigen:

1 SingletonNode    1 * ROOT 
    2 EnumerateCollectionNode  3  - FOR fromItem IN fromCollection /* full collection scan */ 
    8 IndexNode     3  - FOR toItem IN toCollection /* hash index scan */ 

Um nur die Arbeit an vor kurzem eingeführten Artikel in fromCollection ist relativ einfach: Einfach einen Zeitstempel der Importzeit mit allen Ecken hinzufügen und Verwendung:

FOR fromItem IN fromCollection 
    FILTER fromItem.timeStamp > @lastRun 
    FOR toItem IN toCollection 
     FILTER fromItem.fromAttributeValue == toItem.toAttributeValue 
     INSERT { _from: fromItem._id, _to: toItem._id, otherAttributes: {}} INTO edgeCollection 

und Natürlich setzen Sie einen Skipplistenindex auf das timeStamp Attribut in fromCollection.

Dies sollte wunderbar funktionieren, um neue Vertices in der fromCollection zu entdecken. Es wird neue Scheitelpunkte in toCollection übersehen, die mit alten Scheitelpunkten in fromCollection verknüpft sind.

Sie können diese entdecken, indem die Rollen der fromCollection und die toCollection in Ihrer Abfrage Vertauschung (Sie den Index auf fromAttributeValue in fromCollection nicht vergessen) und die Erinnerung nur in Kanten setzen, wenn die von Vertex alt ist, wie in:

FOR toItem IN toCollection 
    FILTER toItem.timeStamp > @lastRun 
    FOR fromItem IN fromCollection 
     FILTER fromItem.fromAttributeValue == toItem.toAttributeValue 
     FILTER fromItem.timeStamp <= @lastRun 
     INSERT { _from: fromItem._id, _to: toItem._id, otherAttributes: {}} INTO edgeCollection 

Diese beiden zusammen sollten tun, was Sie wollen. Hier finden Sie das Beispiel here.

+0

Danke Max! Ein potenzielles Problem bei der Verwendung des Zeitstempels besteht darin, dass die verschiedenen Sammlungen mit unterschiedlichen Raten importiert werden, so dass Daten in der 'fromCollection' möglicherweise letzte Nacht importiert wurden, aber Daten in der' toCollection' vor einer Stunde importiert wurden. Darüber hinaus müssen neue Daten manchmal mit Daten verknüpft werden, die vor langer Zeit importiert wurden. Dies würde funktionieren, wenn sowohl 'fromItem' als auch 'toItem' zuvor importiert wurden, aber nicht nur für eins. Mein Team hat seither eine deterministische Schlüsselregel für Kanten entwickelt, so dass Duplikation kein Problem ist - jetzt ist es nur die Leistung der Einfügung. –

Verwandte Themen