2010-06-09 12 views
18

Ho un datastore con circa 1.000.000 di entità in un modello. Voglio prendere 10 entità casuali da questo.Recupero di un record casuale dal datastore di Google App Engine?

Non sono sicuro di come farlo? qualcuno può aiutare?

+0

possibile duplicato di [ricerca per N record casuali su datastore Appengine] (http://stackoverflow.com/questions/1105004/querying-for-n-random-records-on-appengine-datastore) –

risposta

21

Assegnare a ogni entità un numero casuale e memorizzarlo nell'entità. Quindi interrogare per dieci record il cui numero casuale è maggiore (o minore) di un altro numero casuale.

Questo non è del tutto casuale, tuttavia, poiché le entità con numeri casuali nelle vicinanze tendono a presentarsi insieme. Se vuoi battere questo, fai dieci query basate su dieci numeri casuali, ma questo sarà meno efficiente.

+0

Esattamente a destra. Potrebbe voler menzionare l'intervallo (0..1 è standard) per i numeri casuali. –

+4

Una possibilità di aumentare la casualità senza danneggiare l'efficienza in fase di lettura sarebbe quella di accodare un'attività per assegnare nuovi numeri casuali alle entità recuperate, quindi se si colpisce di nuovo una di esse non si avranno gli stessi vicini. – geoffspear

+0

@NickJohnson potresti chiarire la gamma standard? Scusa, non ho capito cosa intendevi per (0..1)? Inoltre, per tutti e due: sono preoccupato di usare il mio filtro di disuguaglianza per questa operazione (perché in alcune query ho bisogno che sia casuale ma allo stesso tempo eseguo un filtro di uguaglianza su un'altra proprietà). Quanto è male fare 10 query, è fondamentalmente 10 volte il costo? – iceanfire

3

La risposta di Jason Hall e the one here non sono orribili, ma come dice lui, non sono nemmeno casuali. Anche fare dieci domande non sarà casuale se, per esempio, i numeri casuali sono tutti raggruppati insieme. Per mantenere le cose veramente casuale, qui ci sono due possibili soluzioni:

Soluzione 1

Assegnare un indice a ciascun oggetto archivio dati, tenere traccia dell'indice di massima, e selezionerà casualmente un indice ogni volta che si desidera ottenere un record a caso:

MyObject.objects.filter('index =', random.randrange(0, maxindex+1))

Upside: veramente casuale. Veloce.

Lato inferiore: È necessario mantenere correttamente gli indici durante l'aggiunta e l'eliminazione di oggetti, che possono rendere entrambe le operazioni un'operazione O (N).

Soluzione 2

Assegnare un numero casuale per ogni numero datastore al momento della creazione. Quindi, per ottenere un record casuale la prima volta, eseguire una query per un record con un numero casuale maggiore di un altro numero casuale e ordinare i numeri casuali (ad esempio MyObject.order('rand_num').filter('rand_num >=', random.random())). Quindi salvare quella query come un cursore nel memcache. Per ottenere un record casuale dopo la prima volta, carica il cursore dal memcache e vai all'elemento successivo. Se non c'è nessun articolo dopo il primo, eseguire nuovamente la query.

Per impedire la ripetizione della sequenza di oggetti, su ogni datastore letto, fornire all'entità la lettura di un nuovo numero casuale e salvarlo nuovamente nel datastore.

Up-side: Davvero casuale. Nessun indice complesso da mantenere.

Down-side: È necessario tenere traccia di un cursore. Hai bisogno di fare un put ogni volta che ottieni un record casuale.

+0

"Anche fare dieci query non sarà casuale se, per esempio, i numeri casuali sono tutti raggruppati insieme" - Presumo che tu stia parlando dei numeri casuali che sono stati assegnati alle righe del datastore. Questo è solo un problema per un numero limitato di record: la deviazione standard degli intervalli tra i valori si riduce man mano che il numero di valori aumenta, fino al punto in cui è statisticamente insignificante. La soluzione 1 richiede un contatore monotonico, un'operazione lenta e costosa su App Engine. La soluzione 2 utilizza la selezione senza sostituzione, che è diversa da quella richiesta dall'OP. –

+0

Giusto, l'approccio ingenuo si interrompe se non ci sono molti record o se li stai recuperando ad un ritmo elevato. Inoltre, una volta impostati i valori rand_num, la loro distribuzione è fissa. Non otterrai una buona distribuzione uniforme e ci saranno alcuni record che verranno selezionati solo di rado. – speedplane

+0

No, questo era il mio punto: più grande è il numero di record, minore è la deviazione standard in intervallo. Cioè, ci saranno proporzionalmente meno entità a cui vengono assegnati intervalli anormalmente piccoli. Anche il suggerimento di Wooble di riassegnare i numeri dopo aver selezionato un record avrebbe aiutato a contrastarlo. –

Problemi correlati