Ottimizzazione della gerarchia su Google Appengine Datastore
-
06-07-2019 - |
Domanda
Ho dei dati gerarchici archiviati nell'archivio dati usando un modello simile al seguente:
class ToolCategories(db.Model):
name = db.StringProperty()
parentKey = db.SelfReferenceProperty(collection_name="parent_category")
...
...
Voglio stampare tutti i nomi delle categorie preservando la gerarchia, diciamo in una forma come questa:
--Information Gathering
----OS Fingerprinting
----DNS
------dnstool
----Port Scanning
------windows
--------nmap
----DNS3
----wireless sniffers
------Windows
--------Kismet
Per fare quanto sopra ho usato una semplice ricorsione usando la capacità di referenziamento di ritorno:
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)
Dato che sono molto nuovo nella programmazione del motore dell'app (quasi 3 giorni da quando ho iniziato a scrivere il codice), non sono sicuro che questo sia il modo più ottimizzato dal punto di vista dell'accesso a Datastore per fare il lavoro desiderato.
È questo il modo migliore? se non ciò che è?
Soluzione
Hai un approccio molto ragionevole! Il mio avvertimento principale sarebbe quello che ha poco a che fare con GAE e molto con Python: non costruire una stringa da pezzi con +
o + =
. Piuttosto, fai un elenco di pezzi di stringa (con append
o extender
o comprendi la lista & amp; c) e quando hai finito ti unisci per la stringa finale risultato con '' .join (lista)
o simili. Anche se le recenti versioni di Python si impegnano a fondo per ottimizzare intrinsecamente le prestazioni O (N al quadrato)
dei loop +
o + =
, alla fine tu stai sempre meglio costruendo elenchi di stringhe lungo il percorso e '' .join
inserendoli alla fine!
Altri suggerimenti
Il principale svantaggio del tuo approccio è che, poiché stai utilizzando l'elenco di adiacenza " per rappresentare gli alberi, è necessario eseguire una query di archivio dati per ciascun ramo dell'albero. Le query sui datastore sono piuttosto costose (circa 160 ms ciascuna), quindi costruire l'albero, in particolare se è grande, potrebbe essere piuttosto costoso).
Esiste un altro approccio, che è essenzialmente quello adottato dall'archivio dati per rappresentare i gruppi di entità: invece di archiviare solo la chiave padre, memorizzare l'intero elenco di antenati usando ListProperty:
class ToolCategories(db.Model):
name = db.StringProperty()
parents = db.ListProperty(db.Key)
Quindi, per costruire l'albero, puoi recuperare l'intera cosa in un'unica query:
q = ToolCategories.all().filter('parents =', root_key)