Domanda

Si consideri un'applicazione GAE (Python), che consente agli utenti di commentare le canzoni. Il numero previsto di utenti è 1.000.000. Il numero atteso di canzoni è 5.000.

L'applicazione deve essere in grado di:

  • Dare il numero di canzoni che un utente ha commentato
  • Dare il numero di utenti che hanno commentato in una canzone

La gestione del contatore deve essere transazionale in modo che essi riflettano sempre i dati sottostanti.

Sembra applicazioni GAE devono mantenere questi tipi di conteggi calcolati in ogni momento in quanto l'interrogazione per loro al momento della richiesta sarebbe inefficiente.

Il mio modello di dati

class Song(BaseModel):
    name = db.StringProperty()
    # Number of users commenting on the song
    user_count = db.IntegerProperty('user count', default=0, required=True)
    date_added = db.DateTimeProperty('date added', False, True)
    date_updated = db.DateTimeProperty('date updated', True, False)

class User(BaseModel):
    email = db.StringProperty()
    # Number of songs commented on by the user
    song_count = db.IntegerProperty('song count', default=0, required=True)
    date_added = db.DateTimeProperty('date added', False, True)
    date_updated = db.DateTimeProperty('date updated', True, False)

class SongUser(BaseModel):
    # Will be child of User
    song = db.ReferenceProperty(Song, required=True, collection_name='songs')
    comment = db.StringProperty('comment', required=True)
    date_added = db.DateTimeProperty('date added', False, True)
    date_updated = db.DateTimeProperty('date updated', True, False)

Codice
Questo gestisce conteggio canzone dell'utente transazionale, ma non conta utente del brano.

s = Song(name='Hey Jude')
s.put()

u = User(email='me@example.com')
u.put()

def add_mapping(song_key, song_comment, user_key):
    u = User.get(user_key)

    su = SongUser(parent=u, song=song_key, song_comment=song_comment, user=u);
    u.song_count += 1

    u.put()
    su.put()

# Transactionally add mapping and increase user's song count
db.run_in_transaction(add_mapping, s.key(), 'Awesome', u.key())

# Increase song's user count (non-transactional)
s.user_count += 1
s.put()

La domanda è:? Come faccio a gestire entrambi i contatori transazionale

Sulla base della mia comprensione questo sarebbe impossibile, poiché l'utente, Song, e SongUser dovrebbe essere una parte della stessa gruppo di un'entità . Non possono essere in un gruppo un'entità perché poi tutti i miei dati sarebbero in un gruppo e non potrebbe essere distribuito dall'utente.

È stato utile?

Soluzione

È davvero non dovrebbe avere preoccuparsi di gestire conteggio degli utenti, di canzoni su cui hanno commentato all'interno di una transazione, perché sembra improbabile che un utente sarebbe in grado di commentare più di una canzone alla volta, giusto?

Ora, è sicuramente il caso che molti utenti potrebbero essere commentando la stessa canzone in una sola volta, in modo che è dove si deve preoccupare di fare in modo che i dati non è fatta non valida da una condizione di competizione.

Tuttavia, se si mantiene il conteggio del numero di utenti che hanno commentato su una canzone dentro l'entità Song, e bloccare l'entità con una transazione, che si sta per ottenere molto alto lizza per quella entità e datastore timeout renderanno voi l'applicazione hanno un sacco di problemi.

Questa risposta per questo problema è contatori sharded .

Al fine di fare in modo che è possibile creare una nuova entità SongUser e aggiornamento del contatore sharded il relativo Song, si dovrebbe prendere in considerazione che l'entità SongUser hanno la relativa canzone come un genitore. Questo li metterà nello stesso gruppo di entità ed entrambi si può creare il SongUser e aggiornato il contatore sharded nella stessa transazione. Il rapporto del SongUser all'Utente che l'ha creata può essere tenuto in un ReferenceProperty.

Per quanto riguarda la sua preoccupazione per i due aggiornamenti (quella transazionale e l'aggiornamento utente) non sia successo, che è sempre una possibilità, ma dato che o aggiornamento può fallire, è necessario avere una corretta gestione delle eccezioni per garantire che sia avere successo. Questo è un punto importante: l'in-transazione-aggiornamenti non sono garantiti per avere successo. È possibile ottenere un'eccezione TransactionfailedError se l'operazione non può completare per qualsiasi motivo.

Quindi, se la transazione viene completata senza sollevare un'eccezione, eseguire l'aggiornamento per l'utente in una transazione. Che vi porterà tentativi automatici dell'aggiornamento in uso, dovrebbe verificarsi un errore. A meno che non ci sia qualcosa sui possibili contesa sull'entità utente che non capisco, il possiblity che non finirà per avere successo è surpassingly piccolo . Se questo è un rischio inaccettabile, quindi non credo che quel AppEngine ha una soluzione perfetta a questo problema per voi.

In primo luogo porsi: è davvero così male se il conteggio di canzoni che qualcuno ha commentato è fuori per uno? E 'questo come critica come l'aggiornamento di un saldo del conto bancario o il completamento di un magazzino di vendita?

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