Effiziente Datenbankabfrage nach Vorfahren in einem azyklischen gerichteten Graphen

8

Nehmen wir an, ich habe einen azyklischen gerichteten Graphen wie einen Familienbaum (nicht wirklich ein Baum, da ein Kind zwei Eltern hat). Ich möchte eine Darstellung dieses Graphen in einer relationalen -Datenbank platzieren, damit alle Vorfahren eines Knotens und alle Nachkommen eines Knotens schnell berechnet werden können. Wie würden Sie diese Grafik darstellen? Wie würden Sie alle Nachkommen abfragen? Wie würden Sie Knoten und Beziehungen einfügen und entfernen? Welche Annahmen treffen Sie bezüglich der Daten?

Die beste Lösung hat das beste große O für die Anzahl der select/insert/delete -Anweisungen, die Sie für die Abfrage von Vorfahren und Nachkommen ausführen, wobei Bindungen durch das beste große O für die gesamte Laufzeit unterbrochen werden, wobei Bindungen durch Platzanforderungen unterbrochen sind.

Mein Kollege hat mir diese Frage gestellt. Ich habe eine Lösung, aber im schlimmsten Fall ist es exponentiell, also wollte ich sehen, wie andere Leute es lösen würden.

Bearbeiten

Geklärte relationale Datenbank. Diese Frage ist trivial (und langweilig), wenn Sie Graph-Datenbanken mit integrierten transitiven Closures verwenden.

    
Dave Aaron Smith 20.09.2010, 20:56
quelle

5 Antworten

6

Wenn selects & gt; manipulations , und besonders Unterbaum wählt (alle Vorfahren, alle Nachkommen) Ich würde für eine Closure -Tabelle Ansatz gehen. Ja, eine Explosion von Pfaden in Ihrer Pfad-Tabelle, aber es liefert Ergebnisse schnell (im Gegensatz zum Adjazenzmodell) und hält Updates auf relevante Teile beschränkt (im Gegensatz zu 50% Update mit verschachtelten Sets).

Bill Karwin hat eine schöne Präsentation online über Vor- und Nachteile verschiedener Modelle, siehe Ссылка (Folie 48 ist eine Übersicht).

    
Wrikken 20.09.2010, 21:18
quelle
2

Für DAGs in SQL-Datenbanken schien es nur zwei Lösungen zu geben:

  1. Rekursive WITH-Klausel.

  2. Sperrung der Transaktion

Ich kenne kein praktisches Diagrammbeschriftungsschema (wie verschachtelte Mengen, Intervalle oder materialisierte Pfade)

    
Tegiri Nenashi 23.09.2010 16:41
quelle
1

RDBMS: s sind nicht wirklich dafür ausgelegt, mit dieser Art von Daten umzugehen. Die offensichtliche Wahl ist, stattdessen eine Graphdatenbank zu verwenden, dann ist es nicht nötig, den Graphen in eine andere Repräsentation zu übersetzen, die Sie verwenden eine Graph-API den ganzen Weg. Es gibt eine gute Präsentation von Marko Rodriguez, die die Auswirkungen des zugrundeliegenden Datenmodells im Umgang mit Graphen-Traversalen erklärt, siehe Das Graph Traversal Programming Pattern wenn du tiefer hinein schauen willst.

Ich habe vor einiger Zeit ein einfaches Beispiel für die Behandlung von DAGs mit der Neo4j Graph-Datenbank geschrieben, die für Sie nützlich sein könnte .

    
nawroth 20.09.2010 22:46
quelle
1

"Wie würden Sie diese Grafik darstellen?"

  • VAR NODES RELATION {Knoten: Irgendwann} KEY {Knoten};
  • VAR-EDGE-RELATION {parentNode: something childNode: irgendwas} KEY {parentNode childNode};
  • CONSTRAINT NO_CYCLES IS_EMPTY (TCLOSE (KANTEN) WHERE parentNode = childNode);

"Wie würden Sie alle Nachkommen abfragen?"

TCLOSE (KANTEN) WHERE parentNode = somevalue;

"Wie würden Sie Knoten und Beziehungen einfügen und entfernen?"

  • EINFÜGEN IN KANTEN RELATION {TUPLE {parentNode somevalue chlidNode somevalue}};
  • DELETE EDGES WHERE deleteCondition;

"Welche Annahmen treffen Sie bezüglich der Daten?"

Welche Art von Annahmen gibt es? Sie haben alles spezifiziert, was zu spezifizieren ist, indem Sie "gerichteter azyklischer Graph" sagen.

    
Erwin Smout 21.09.2010 11:04
quelle
0

In einer relationalen Datenbank würde ich für jeden Knoten speichern:

  • Vater
  • Kinder
  • Vorfahren

Mit Index für alles und voller Index für Vorfahren

Anfrage für:

  • alle Vorfahren:
    • O (log n) (finde den Knoten, dann bist du fertig)
  • alle Nachkommen:
    • O (vollständige Indexsuche nach Vorfahren) (abhängig von der Datenbank)
  • füge neuen Knoten hinzu / lösche Knoten (ohne childs):
    • O (1) für Vater + Vorfahren
    • O (log n) um Vater
    • zu finden
    • update vaters childs O (| vaters childs |)
  • Knoten verschieben (schwierig) :
    • O (1) um Vater
    • zu aktualisieren
    • O (log n) um alte / neue Väter zu finden
    • update vaters childs zweimal O (| vaters childs |)
    • update Vorfahren aller Nachkommen (einfach ersetzen): O (| Abkömmlinge | * | Tiefe max Baum |) (Tiefe-Max: ersetzen und erstellen große Zeichenfolge von Max-Länge (Tiefe-Max))

Die Gesamtkomplexität hängt ab von:

  • Tiefe des Baumes
  • ausgewogener Baum?
  • Anzahl der Kinder? (im Durchschnitt, Max ...)
  • Komplexität der Operation in einer gegebenen relationalen Datenbank

Nur für SELECT, effizient, aber schwierig für Aktualisierungen.

In der Praxis: Arbeite am RAM-Baum (mit muddaged zum Beispiel alles im RAM) und wenn nicht möglich, kaufe mehr RAM, von "cur" tree in kleineren Bäumen.

Alle Nachkommen werden sowieso viel kosten, mit Unterbäumen können Sie Nachkommen mit der maximalen Tiefe D haben, ohne alle zu haben.

Sie "springen" von Unterbaum zu Unterbaum: mehr Anfragen, aber schnellere UND Knoten viel schneller bewegen (nur einen Unterbaum aktualisieren).

    
Loïc Février 23.09.2010 14:46
quelle