2009-06-21 9 views
4

Ich habe hierarchisch im Datenspeicher gespeicherten Daten mit Hilfe eines Modells, das wie folgt aussieht:Hierarchy Optimierung auf Google App Engine-Datenspeicher

class ToolCategories(db.Model): 
    name = db.StringProperty() 
    parentKey = db.SelfReferenceProperty(collection_name="parent_category") 
    ... 
    ... 

Ich möchte alle Kategorienamen drucken, die Hierarchie zu bewahren, sagen wir in irgendeiner Form wie diese :

--Information Gathering 
----OS Fingerprinting 
----DNS 
------dnstool 
----Port Scanning 
------windows 
--------nmap 
----DNS3 
----wireless sniffers 
------Windows 
--------Kismet 

die oben genannten tun ich einfach Rekursion unter Verwendung der Rücken Referenzierung Fähigkeit verwendet haben:

class GetAllCategories (webapp.RequestHandler) : 


     def RecurseList(self, object, breaks) : 
       output = breaks + object.name + "</br>" 
       for cat in object.parent_category: 
         output = output + self.RecurseList(cat, breaks + "--") 

       return output 



     def get (self) : 
       output = "" 
       allCategories = ToolCategories.all().filter(' parentKey = ', None) 
       for category in allCategories : 
         output = output + self.RecurseList(category, "--") 

       self.response.out.write(output) 

Da ich sehr neu in der App-Engine-Programmierung bin (kaum 3 Tage, seit ich Code zu schreiben begann), bin ich mir nicht sicher, ob dies der optimalste Weg vom Datastore-Zugriffspunkt zum gewünschten Job ist.

Ist das der beste Weg? wenn nicht was ist?

Antwort

2

Sie haben einen sehr vernünftigen Ansatz! Mein Hauptvorbehalt wäre einer, der wenig mit GAE und viel mit Python zu tun hat: nicht eine Schnur aus Stücken mit + oder += bauen. Stattdessen erstellen Sie eine Liste mit Stringteilen (mit append oder extend oder Listenkompromittierungen & c) und wenn Sie fertig sind, verbinden Sie es für das endgültige String-Ergebnis mit ''.join(thelist) oder dergleichen. Obwohl aktuelle Python-Versionen sich bemühen, die an sich O(N squared) Performance der + oder += Loops zu optimieren, sind Sie am Ende immer besser dran, Listen von Strings auf dem Weg zu erstellen und ''.join bis zum Ende auf!

+0

@Jake, vielen Dank für die schnelle Annahme! Lustig, um ein Akzeptieren ohne eine Verbesserung zu bekommen, obwohl ich denke, es ist das erste Mal, dass es mir in 2 Monaten auf SO passiert ist ;-). –

+0

Ah, ich wusste, dass upvote-less akzeptieren konnte nicht dauern ...! -) –

+0

Danke für den Vorschlag Alex! Ich werde Änderungen vornehmen und die Join() auf der endgültigen Liste verwenden. Nur eine kurze Erläuterung benötigt: Aus Sicht eines Datenspeichers mit der Reference-Eigenschaft auf verwandte Daten zugreifen ist der schnellste Weg, um es zu tun - habe ich Recht? – MathOldTimer

4

Der Hauptnachteil Ihres Ansatzes besteht darin, dass Sie eine Datenspeicherabfrage für jeden Zweig des Baums durchführen müssen, da Sie die Methode der "Adjazenzliste" zur Darstellung von Bäumen verwenden. Datenspeicherabfragen sind ziemlich teuer (jeweils etwa 160 ms), so dass der Baum, insbesondere wenn er groß ist, ziemlich teuer sein könnte).

Es gibt einen anderen Ansatz, der im Wesentlichen die man durch die Datenspeicherentität Gruppen für die Darstellung genommen ist: Anstatt nur die Speicherung der übergeordneten Schlüssel, speichern Sie die gesamte Liste der Vorfahren mit einem Listproperty:

class ToolCategories(db.Model): 
    name = db.StringProperty() 
    parents = db.ListProperty(db.Key) 

Dann zu Konstruieren Sie den Baum, können Sie das gesamte Ding in einer einzigen Abfrage abrufen:

q = ToolCategories.all().filter('parents =', root_key) 
+0

Nick, Danke für den Zeiger! Als Appengine-Neuling ist das Problem, dass ich nicht in der Lage bin, die Anzahl der tatsächlichen Datastore-Abfragen für jede Datastore-Zugriffsanweisung zu visualisieren, die ich schreibe. Mit SQL war dies einfach zu machen und somit könnte man die "Kosten" einer Anfrage abschätzen. Ich konnte nirgends eine gute Dokumentation über "Datenspeicher-Abfragekosten" finden und bin daher mit Optimierungsproblemen beschäftigt. Gibt es irgendwo ein detailliertes Dokument? – MathOldTimer

+0

Alle Datenspeicherabfragen haben Kosten, die proportional zur Anzahl der zurückgegebenen Einträge sind, mit einem (large-ish) Konstantenfaktor für den Umlauf zum Datenspeicher. Daher müssen Sie meistens nur die Anzahl der Rundreisen und die Anzahl der zurückgegebenen Entitäten addieren und versuchen, beide zu optimieren. Im Fall Ihres ursprünglichen Beispiels wird das Problem durch die impliziten Datenspeichervorgänge, die beim Abrufen der ReferenceProperty-Auflistung ausgeführt werden, noch verschärft. –

+3

Übrigens sehe ich dies als einen der Vorteile des Datenspeichers an: Während die Kosten einer SQL-Abfrage aus der SELECT-Anweisung nicht offensichtlich sind und von der Art der Daten und sogar der einzelnen DB abhängen, hat eine Datenspeicherabfrage immer die gleichen Kosten , unabhängig von diesen Variablen. –