Domanda

Mi chiedo quale sarebbe il modo migliore per progettare un'applicazione social in cui i membri fanno attività e seguono le attività di altri membri utilizzando Google AppEngine.

Per essere più specifici supponiamo che abbiamo queste entità:

  • Utenti che hanno amici
  • Attività che rappresentano azioni eseguite dagli utenti (supponiamo che ciascuno abbia un messaggio stringa e una Proprietà di riferimento per l'utente proprietario o che possa utilizzare l'associazione padre tramite la chiave dell'appengine)

La parte difficile è seguire le attività del tuo amico, il che significa aggregare le ultime attività di tutti i tuoi amici. Normalmente, sarebbe un join tra la tabella delle attività e l'elenco degli amici, ma non è un progetto praticabile su appengine in quanto non esiste un join che simula che richiederà l'accensione di N query (dove N è il numero di amici) e quindi l'unione in memoria - molto costoso e probabilmente supererà la scadenza della richiesta ...)

Attualmente sto pensando di implementarlo usando le code di posta in arrivo in cui la creazione di una nuova attività attiverà un processo in background che inserirà la chiave della nuova attività nella casella di posta in arrivo " di ogni utente seguente:

  • Ottenere " Tutti gli utenti che seguono X " è una possibile query dell'appengine
  • Input batch non molto costoso in una nuova "Posta in arrivo" entità che sostanzialmente memorizza le tuple (utente, chiave attività).

Sarò felice di sentire il pensiero su questo design o suggerimenti alternativi ecc.

È stato utile?

Soluzione

Dai un'occhiata a Creazione di app complesse e scalabili su App Engine ( pdf ), a discorso affascinante tenuto a Google I / O da Brett Slatkin. Risolve il problema della creazione di un servizio di messaggistica scalabile come Twitter.

Ecco la sua soluzione utilizzando una proprietà dell'elenco:

class Message(db.Model):
    sender = db.StringProperty()
    body = db.TextProperty()

class MessageIndex(db.Model):
    #parent = a message
    receivers = db.StringListProperty()

indexes = MessageIndex.all(keys_only = True).filter('receivers = ', user_id)
keys = [k.parent() for k in indexes)
messages = db.get(keys)

Questa query solo chiave trova gli indici dei messaggi con un ricevitore uguale a quello specificato senza deserializzare e serializzare l'elenco di destinatari. Quindi usi questi indici solo per afferrare i messaggi che desideri.

Ecco nel modo sbagliato per farlo:

class Message(db.Model):
    sender = db.StringProperty()
    receivers = db.StringListProperty()
    body = db.TextProperty()

messages = Message.all().filter('receivers =', user_id)

Questo è inefficiente perché le query devono decomprimere tutti i risultati restituiti dalla query. Quindi, se hai restituito 100 messaggi con 1.000 utenti in ciascun elenco di destinatari, dovresti deserializzare 100.000 (100 x 1000) valori delle proprietà dell'elenco. Troppo costoso in termini di latenza degli archivi dati e CPU.

All'inizio ero piuttosto confuso da tutto ciò, quindi ho scritto un breve tutorial sull'uso della proprietà list . Divertiti :)

Altri suggerimenti

Non so se sia il miglior design per un'applicazione social, ma jaiku è stato trasferito su App Engine dal suo creatore originale quando la società è stata acquisita da Google, quindi dovrebbe essere ragionevole.

Vedi la sezione Attori e tigri e orsi, oh mio! in design_funument.txt . Le entità sono definite in common / models.py e le query sono in common / api.py .

Robert, sulla tua soluzione proposta:

messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body])

Penso che ndb.TextProperty " body " non può essere utilizzato con le proiezioni perché non è indicizzato. Le proiezioni supportano solo le proprietà indicizzate. La soluzione valida sarebbe quella di mantenere le 2 tabelle: Message e MessageIndex.

Penso che ora questo possa essere risolto con le nuove query di proiezione in NDB.

class Message(ndb.Model):
    sender = ndb.StringProperty()
    receivers = ndb.StringProperty(repeated=True)
    body = ndb.TextProperty()

messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body])

Ora non devi affrontare i costi costosi della deserializzazione della proprietà dell'elenco.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top