2010-06-09 3 views
18

J'ai un magasin de données avec environ 1 000 000 entités dans un modèle. Je veux chercher 10 entités aléatoires de ceci.Récupérer un enregistrement aléatoire à partir du magasin de données Google App Engine?

Je ne sais pas comment faire cela? quelqu'un peut-il aider?

+0

duplication possible de [Recherche de N enregistrements aléatoires sur le magasin de données Appengine] (http://stackoverflow.com/questions/1105004/querying-for-n-random-records-on-appengine-datastore) –

Répondre

21

Affectez à chaque entité un nombre aléatoire et stockez-la dans l'entité. Ensuite, recherchez dix enregistrements dont le nombre aléatoire est supérieur (ou inférieur) à un autre nombre aléatoire. Cependant, cela n'est pas totalement aléatoire, car les entités ayant des nombres aléatoires proches auront tendance à apparaître ensemble. Si vous voulez battre ceci, faites dix requêtes basées sur une dizaine de nombres aléatoires, mais cela sera moins efficace.

+0

Exactement. Peut vouloir mentionner la gamme (0..1 est standard) pour les nombres aléatoires. –

+4

Une possibilité d'augmenter le caractère aléatoire sans nuire à l'efficacité du temps de lecture serait de mettre en file d'attente une tâche pour assigner de nouveaux nombres aléatoires aux entités que vous avez récupérées, donc si vous en frappez une nouvelle, vous n'obtiendrez pas les mêmes voisins. – geoffspear

+0

@NickJohnson pourriez-vous préciser sur la gamme standard? Désolé, je n'ai pas compris ce que vous vouliez dire par (0..1)?De plus, à tous les deux: Je m'inquiète d'utiliser mon filtre d'inégalité pour cette opération (parce que dans certaines requêtes j'ai besoin d'être aléatoire mais en même temps lancer un filtre d'égalité sur une autre propriété). À quel point est-ce mal de faire 10 requêtes, est-ce fondamentalement 10 fois le coût? – iceanfire

3

La réponse de Jason Hall et the one here ne sont pas horribles, mais comme il le mentionne, ils ne sont pas vraiment aléatoires non plus. Même faire dix requêtes ne sera pas aléatoire si, par exemple, les nombres aléatoires sont tous regroupés. Pour garder les choses vraiment au hasard, voici deux solutions possibles:

Solution 1

Assigner un index à chaque objet datastore, garder une trace de l'indice maximum et choisir au hasard un index à chaque fois que vous voulez obtenir un dossier au hasard:

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

Upside: Vraiment au hasard. Vite.

Défaut: Vous devez gérer correctement les index lors de l'ajout et de la suppression d'objets, ce qui peut rendre les deux opérations O (N).

Solution 2

attribuer un numéro aléatoire à chaque numéro de datastore lors de sa création. Ensuite, pour obtenir un enregistrement aléatoire la première fois, recherchez un enregistrement avec un nombre aléatoire supérieur à un autre nombre aléatoire et ordonnez par les nombres aléatoires (c'est-à-dire MyObject.order('rand_num').filter('rand_num >=', random.random())). Puis enregistrez cette requête en tant que curseur dans le memcache. Pour obtenir un enregistrement aléatoire après la première fois, chargez le curseur du memcache et passez à l'élément suivant. S'il n'y a aucun élément après le premier, réexécutez la requête.

Pour empêcher la répétition de la séquence d'objets, à chaque banque de données lue, donnez à l'entité que vous venez de lire un nouveau nombre aléatoire et enregistrez-la dans le magasin de données.

Vers le haut: Vraiment aléatoire. Aucun indice complexe à maintenir.

Face inférieure: Nécessité de garder la trace d'un curseur. Besoin de faire un put chaque fois que vous obtenez un enregistrement aléatoire.

+0

"Même faire dix requêtes ne sera pas aléatoire si, par exemple, les nombres aléatoires sont tous regroupés" - Je présume que vous parlez des nombres aléatoires qui ont été assignés aux lignes de banque de données. Ce n'est qu'un problème pour un petit nombre d'enregistrements - l'écart-type des écarts entre les valeurs diminue à mesure que le nombre de valeurs augmente, au point où il est statistiquement insignifiant. Votre solution 1 nécessite un compteur monotone, ce qui est une opération lente et coûteuse sur App Engine. La solution 2 utilise la sélection sans remplacement, ce qui est différent de ce que le PO demandait. –

+0

À droite, l'approche naïve se décompose s'il n'y a pas beaucoup d'enregistrements ou si vous les récupérez à un taux élevé. En outre, une fois que les valeurs de rand_num sont définies, leur distribution est fixée. Vous n'obtiendrez pas une bonne distribution uniforme et certains dossiers ne seront que rarement sélectionnés. – speedplane

+0

Non, c'était mon point - plus le nombre d'enregistrements que vous avez est grand, plus l'écart-type est petit dans l'intervalle. Autrement dit, il y aura proportionnellement moins d'entités qui ont des intervalles anormalement petits qui leur sont assignés. La suggestion de Wooble de réattribuer des numéros une fois que vous avez sélectionné un enregistrement aiderait également à contrecarrer cela. –