Question

Je suis en train d'écrire une requête qui renvoie des enregistrements GQL N aléatoires d'un type spécifique. Ma mise en œuvre actuelle fonctionne mais nécessite N appels à la datastore. Je voudrais faire 1 appel à la datastore si possible.

Je cède actuellement un nombre aléatoire à tous les types que je mets dans le datastore. Lorsque je fais une recherche pour un enregistrement au hasard que je produis un autre nombre aléatoire et requête pour les enregistrements> rand ORDER BY asc LIMIT 1.

Cela fonctionne, cependant, il retourne seulement 1 dossier, alors je dois faire des requêtes N. Toutes les idées sur la façon de faire une requête? Ce Merci.

Était-ce utile?

La solution

« Sous le capot » un appel de requête de recherche unique ne peut retourner un ensemble de lignes consécutives de certains index. C'est pourquoi certaines requêtes GQL, y compris toute utilisation! =, Développez à plusieurs appels datastore.

N uniformes sélections aléatoires indépendantes ne sont pas (en général) consécutive à un indice.

QED.

Vous pouvez probablement utiliser memcache pour stocker les entités et réduire le coût de l'accaparement N d'entre eux. Ou si vous ne dérange pas les sélections « aléatoires » étant proches dans l'index, sélectionnez un bloc aléatoire choisi de (disons) 100 dans une requête, puis choisissez N au hasard parmi ceux-ci. Puisque vous avez un champ qui est déjà aléatoire, il ne sera pas immédiatement évident pour un étranger que les N éléments sont liés. Au moins, pas jusqu'à ce qu'ils regardent beaucoup d'échantillons et notez que les articles A et Z apparaissent jamais dans le même groupe, parce qu'ils sont plus de 100 à part dans l'indice aléatoire. Et si les permis de performance, vous pouvez re-randomiser vos entités de temps à autre.

Autres conseils

Quel genre de compromis que vous cherchez? Si vous êtes prêt à mettre en place avec une petite baisse de performance sur l'insertion de ces entités, vous pouvez créer une solution pour obtenir N d'entre eux très rapidement.

Voici ce que vous devez faire:

Lorsque vous insérez vos entités, spécifiez la clé. Vous voulez donner des clés à vos entités dans l'ordre, en commençant par 1 et aller de là. (Cela nécessitera un certain effort, comme moteur d'application n'a pas autoincrement () vous aurez donc besoin de garder une trace du dernier id que vous avez utilisé dans une autre entité, nous allons l'appeler un IdGenerator)

Maintenant, quand vous avez besoin N entités aléatoires, générer N nombres aléatoires entre 1 et quel que soit le dernier id que vous avez généré est (votre IdGenerator saura ce sujet). Vous pouvez alors faire un lot obtenir par clé à l'aide des touches N, qui ne nécessite un voyage à la datastore, et sera plus rapide qu'une requête aussi, puisque la clé obtient sont généralement plus rapides que les requêtes, AFAIK.

Cette méthode ne nécessite traiter quelques détails gênants:

  1. Votre IdGenerator pourrait devenir un goulot d'étranglement si vous insérez beaucoup de ces articles à la volée (plus de quelques seconde), ce qui nécessiterait une sorte de mise en œuvre de IdGenerator fragmentées. Si toutes ces données est pré-chargé, ou ne sont pas un volume élevé, vous avez facilement.
  2. Vous trouverez peut-être que certains Id ne fait pas une entité qui lui est associée plus, parce que vous l'avez supprimé ou parce qu'un put () quelque part échoué. Si cela vous est arrivé auriez à saisir une autre entité aléatoire. (Si vous voulez obtenir la fantaisie et de réduire les chances de ce que vous pouvez faire cet identifiant à la disposition du IdGenerator de réutiliser pour « remplir les trous »)

La question se résume à la façon dont vous avez besoin rapidement ces éléments N vs combien de fois vous ajouterez et de les supprimer, et si un peu de complexité supplémentaire vaut ce coup de pouce de la performance.

ressemble à la seule méthode consiste à stocker la valeur de nombre entier aléatoire dans la propriété particulière de chaque entité et l'interrogation à ce sujet. Cela peut se faire tout à fait automatiquement si vous ajoutez simplement une propriété initialisé automatiquement.

Malheureusement, cela nécessitera le traitement de toutes les entités une fois si votre magasin de données est déjà rempli.

Il est bizarre, je sais.

Je suis d'accord à la réponse de Steve, il n'y a pas moyen de récupérer N lignes aléatoires dans une requête.

Cependant, même la méthode de récupération d'une seule entité ne fonctionne pas habituellement telle que la prbability des résultats retournés est réparti uniformément. La probabilité de retour d'une entité donnée dépend de l'écart de celui-ci est le numéro attribué au hasard et le nombre aléatoire suivant supérieur. Par exemple. si les nombres aléatoires 1,2, et 10 ont été assignés (et aucun des numéros 3-9), l'algorithme retournera « 2 » 8 fois plus souvent que « 1 ».

Je l'ai fixé cette façon de expensice un peu plus. Si quelqu'un est intéressé, je suis heureux de partager

Je viens d'avoir le même problème. Je décidé de ne pas attribuer à mes ID déjà entrées existantes et datastore fait cela, comme je l'ai déjà eu l'totalCount d'un compteur fragmentées.

Ceci permet de sélectionner les entrées "de comptage" de entrées "totalCount", triées par touche .

    # select $count from the complete set
    numberlist = random.sample(range(0,totalcount),count)
    numberlist.sort()

    pagesize=1000

    #initbuckets
    buckets = [ [] for i in xrange(int(max(numberlist)/pagesize)+1) ]
    for k in numberlist:
        thisb = int(k/pagesize)
        buckets[thisb].append(k-(thisb*pagesize))
    logging.debug("Numbers: %s. Buckets %s",numberlist,buckets)

    #page through results.

    result = []
    baseq =  db.Query(MyEntries,keys_only=True).order("__key__")
    for b,l in enumerate(buckets):
        if len(l) > 0: 
            result += [ wq.fetch(limit=1,offset=e)[0] for e in l ]

        if b < len(buckets)-1: # not the last bucket
            lastkey  = wq.fetch(1,pagesize-1)[0]
            wq = baseq.filter("__key__ >",lastkey)

Attention que cela me paraît un peu complexe, et je ne suis toujours pas conviced que je n'avez pas hors par une ou plusieurs erreurs hors par-x.

Et méfiez-vous que si le nombre est proche de TOTALCOUNT cela peut être très coûteux. Et méfiez-vous que des millions de lignes, il pourrait ne pas être possible de le faire dans les limites de temps AppEngine.

Si je comprends bien, vous avez besoin de récupérer N instance aléatoire.

Il est facile. Il suffit de n'interroger avec les touches seulement. Et faire random.choice N fois sur le résultat de la liste des clés. Ensuite, obtenir des résultats en allant chercher sur les touches.

keys = MyModel.all(keys_only=True)

n = 5 # 5 random instance

all_keys = list(keys)
result_keys = []

for _ in range(0,n) 
    key = random.choice(all_keys)
    all_keys.remove(key)
    result_keys.append(key)

# result_keys now contain 5 random keys.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top