2011-02-28 7 views
9

Sto ancora imparando le mie lezioni sulla modellazione dei dati in bigtable/nosql e apprezzerei qualche feedback. Sarebbe corretto dire che dovrei evitare le relazioni genitore-> figlio nella mia modellazione dei dati se ho spesso bisogno di trattare i bambini in modo aggregato tra i genitori?parent-> relazioni figlio in appengine python (bigtable)

Ad esempio, diciamo che sto costruendo un blog a cui un certo numero di autori darà il proprio contributo e che l'un l'altro ha post e ogni post ha tag. Quindi potrei potenzialmente impostare qualcosa del genere:

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    owner = db.ReferenceProperty(Author, 
    collection_name='posts') 
    tags = db.StringListProperty() 

Come ho capito questo creerà un gruppo di entità basato sull'autore padre. Ciò causa inefficienza se per lo più ho bisogno di interrogare i Post per tag che mi aspetto di tagliare su più Autori?

Capisco che fare una query sulle proprietà dell'elenco può essere inefficiente. Diciamo che ogni post ha in media circa 3 tag, ma potrebbe arrivare fino a 7. E mi aspetto che la mia collezione di tag possibili sia tra le poche centinaia. C'è qualche vantaggio nel modificare quel modello in qualcosa del genere?

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    owner = db.ReferenceProperty(Author, 
    collection_name='posts') 
    tags = db.ListProperty(db.Key) 

class Tag(db.Model): 
    name = db.StringProperty() 

O sarei meglio fare qualcosa di simile?

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    owner = db.ReferenceProperty(Author, 
    collection_name='posts') 

class Tag(db.Model): 
    name = db.StringProperty() 

class PostTag(db.Model): 
    post = db.ReferenceProperty(Post, 
    collection_name='posts') 
    tag = db.ReferenceProperty(Tag, 
    collection_name='tags') 

E ultima domanda ... cosa succede se il mio caso d'uso più comune sarà query per i messaggi di più tag. Ad esempio, "trova tutti i post con tag in {'mele', 'arance', 'cetrioli', 'biciclette'}" Uno di questi approcci è più appropriato per una query che cerca post che abbiano una qualsiasi raccolta di tag ?

Grazie, so che era un boccone. :-)

+0

Nessuno dei vostri esempi crea gruppi di entità. Nel primo esempio, stai usando una Reference Reference, che crea un riferimento all'altra entità - questa è mutabile e non implica la proprietà. I riferimenti principali vengono creati specificando l'argomento "principale" per il costruttore per l'entità: consultare questa pagina per i dettagli: http://code.google.com/appengine/docs/python/datastore/entities.html#Entity_Groups_and_Ancestor_Paths –

+0

Ah, grazie Nick. Mi mancava quella parte ... pensavo che fossero i riferimenti a creare la relazione genitore e mancava il fatto che era necessario passare il genitore al costruttore. Questo ha senso ora. –

risposta

5

Qualcosa come il primo o il secondo approccio sono adatti per App Engine.Si consideri la seguente configurazione:

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    author = db.ReferenceProperty(Author, 
    collection_name='posts') 
    tags = db.StringListProperty() 

class Tag(db.Model): 
    post_count = db.IntegerProperty() 

Se si utilizza il tag della stringa (case-normalizzato) come il key_name entità Tag, è possibile interrogare in modo efficiente per i messaggi con un tag specifico, o elencare i tag di un post, o andare a prendere statistiche tag:

post = Post(author=some_author, tags=['app-engine', 'google', 'python']) 
post_key = post.put() 
# call some method to increment post counts... 
increment_tag_post_counts(post_key) 

# get posts with a given tag: 
matching_posts = Post.all().filter('tags =', 'google').fetch(100) 
# or, two tags: 
matching_posts = Post.all().filter('tags =', 'google').filter('tags =', 'python').fetch(100) 

# get tag list from a post: 
tag_stats = Tag.get_by_key_name(post.tags) 

Il terzo approccio richiede ulteriori domande o recupera per la maggior parte delle operazioni di base, ed è più difficile se si desidera eseguire una query per più tag.

+0

fantastico, grazie robert. questo è in realtà come l'ho scritto. ma sono ancora nuovo, quindi non ero sicuro che fosse davvero il modo migliore, quindi apprezzo che tu abbia condiviso la tua esperienza! –

+1

@Bob Ralian, una cosa di cui diffidare sono gli indici che esplodono. Il concetto generale è buono; potresti anche trovare utile il pattern "Relation Index", ma dal momento che la tua lista è molto piccola _e_ vuoi che i tag non abbiano bisogno di un'entità separata. (Http://www.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html) –

2

Vorrei scegliere l'ultimo approccio, perché consente di recuperare un elenco di post direttamente dato un tag.

Il primo approccio rende praticamente impossibile mantenere un insieme di tag canonico. In altre parole, la domanda "quali tag sono attualmente presenti nel sistema" è molto costosa per rispondere.

Il secondo approccio risolve questo problema, ma come ho detto non ti aiuta a recuperare i post con un tag.

gruppi di entità sono un po 'di una bestia misteriosa, ma basti dire che il primo approccio non crea un gruppo di entità, e che sono solo necessari per le operazioni di database transazionale, e talvolta utile per ottimizzare i dati si legge, ma probabilmente non sono necessari in un'applicazione di dimensioni ridotte.

Va detto che qualsiasi approccio che si prende funzionerà bene solo in combinazione con una strategia di caching intelligente. Applicazioni GAE AMARO il caching. Prendi confidenza con la memcache api e impara le operazioni di lettura/scrittura di massa su memcache e sul datastore.

+0

Grazie Trittico. In realtà non sono preoccupato per il problema canonico, poiché lo gestirò durante la convalida prima di salvare. Ri: gruppi di entità, i documenti dicono "Per creare un'entità in un gruppo, dichiari che un'altra entità è il genitore della nuova entità quando la crei." Quindi considero che una relazione genitore-> figlio creerà un gruppo di entità se è dichiarata sul bambino nel momento in cui è stata creata. Capisco che il punto dei gruppi di entità sia per le transazioni. Ma causano latenza/inefficienza per le selezioni attraverso i gruppi di entità? Sono possibili transazioni incrociate? –

+0

Le transazioni tra gruppi non sono possibili, ma se si stanno facendo molte selezioni tra gruppi di entità, è un'indicazione che non si dovrebbero comunque usare. Inoltre, è necessario comprendere che il processo di convalida richiederà la lettura di ogni tag in ogni modello Post nell'archivio dati, se si utilizza il primo approccio. – Triptych

+0

Avrò un modello Tag separato a prescindere. E terrò quelli in memcache. Il primo approccio appena ferito in realtà li lega ma li userebbe invece per dettare stringhe accettabili. Non è necessariamente appropriato per i post in cui selezionerei i tag, ma sarebbe più appropriato per qualcosa come le preferenze di Reader, in cui ho solo bisogno di tirare la lista dei tag. –

Problemi correlati