web-dev-qa-db-fra.com

Comment aller chercher plus de 1000?

Comment puis-je récupérer plus de 1000 enregistrements du magasin de données et les mettre tous dans une seule liste pour les transmettre à Django?

48
Zote

Depuis la version 1.3.6 (publiée le 17 août 2010), vous POUVEZ 

À partir du changelog:

Les résultats des requêtes count () datastore et des décalages de toutes les requêtes datastore ne sont plus limités à 1000.

37
Shay Erlichmen

Pour mémoire, la limite d'extraction de 1000 entrées est maintenant révolue:

http://googleappengine.blogspot.com/2010/02/app-engine-sdk-131-including-major.html

Devis:

Pas plus de 1000 résultats limite - C'est à droite: avec ajout de curseurs et l'aboutissement de nombreux plus petits Stabilité et performance du magasin de données améliorations apportées au cours des derniers mois, nous sommes maintenant assez confiants pour supprimer la limite maximale de résultat au total . Que vous fassiez un aller chercher, itérant ou utilisant un curseur, il y a pas de limite sur le nombre de résultats.

23
Tomasz Zielinski

App Engine vous offre un moyen agréable de "paginer" les résultats par 1000 en plaçant des commandes sur les clés et en utilisant la dernière clé comme décalage suivant. Ils fournissent même un exemple de code ici:

http://code.google.com/appengine/docs/python/datastore/queriesandindexes.html#Queries_on_Keys

Bien que leur exemple répartisse les requêtes sur de nombreuses requêtes, vous pouvez modifier la taille de la page de 20 à 1000 et interroger en boucle en combinant les ensembles de requêtes. De plus, vous pouvez utiliser itertools pour lier les requêtes sans les évaluer avant qu’elles soient nécessaires.

Par exemple, pour compter le nombre de lignes au-delà de 1000:

class MyModel(db.Expando):
    @classmethod
    def count_all(cls):
        """
        Count *all* of the rows (without maxing out at 1000)
        """
        count = 0
        query = cls.all().order('__key__')

        while count % 1000 == 0:
            current_count = query.count()
            if current_count == 0:
                break

            count += current_count

            if current_count == 1000:
                last_key = query.fetch(1, 999)[0].key()
                query = query.filter('__key__ > ', last_key)

        return count
19
JJ Geewax

Chaque fois que cela apparaît comme une limitation, je me demande toujours "pourquoi avez-vous besoin de plus de 1000 résultats?" Saviez-vous que Google ne fournit pas plus de 1 000 résultats? Essayez cette recherche: http://www.google.ca/search?hl=fr&client=firefox-a&rls=org.mozilla:en-US:official&hs=qhu&q=1000+results&start=1000&sa=N I didn ' Je ne le sais pas jusqu’à récemment, car je n’avais jamais pris le temps de cliquer sur la centième page des résultats de la recherche concernant une requête.

Si vous renvoyez plus de 1 000 résultats à l'utilisateur, je pense qu'il y a un problème plus important que le fait que le magasin de données ne vous laisse pas le faire.

Une raison possible (légitime) de nécessiter autant de résultats est si vous effectuez une opération volumineuse sur les données et présentez un résumé (par exemple, quelle est la moyenne de toutes ces données). La solution à ce problème (dont parle Google I/O talk) consiste à calculer les données de synthèse à la volée, au fur et à mesure de leur arrivée, et de les sauvegarder.

18
Tony Arkles

Tu ne peux pas.

Une partie de FAQ indique qu'il est impossible d'accéder au-delà de la ligne 1000 d'une requête. L'augmentation de la valeur "OFFSET" entraînera simplement un ensemble de résultats plus court. 

par exemple, OFFSET 999 -> 1 résultat est renvoyé. 

De Wikipedia: 

App Engine limite le nombre maximal de lignes retourné d'une entité arriver à 1000 lignes par appel de magasin de données. La plupart des sites Web les applications de base de données utilisent la pagination et la mise en cache, et donc ne nécessite pas cela beaucoup de données à la fois, donc ceci est un non-problème dans la plupart des scénarios. [citation nécessaire] Si une application a besoin de plus plus de 1 000 enregistrements par opération, il peut utiliser son propre logiciel côté client ou une page Ajax pour effectuer un opération sur un nombre illimité de rangées.

De http://code.google.com/appengine/docs/whatisgoogleappengine.html

Un autre exemple de limite de service est le nombre de résultats renvoyés par un question. Une requête peut renvoyer au plus 1000 résultats. Des requêtes qui seraient renvoyer plus de résultats que renvoyer le maximum. Dans ce cas, une demande qui effectue une telle requête n'est pas susceptible de renvoyer une demande avant l'expiration du délai, mais la limite est en place pour conserver ressources sur le magasin de données.

De http://code.google.com/appengine/docs/datastore/gqlreference.html

Remarque: Une clause LIMIT a un maximum de 1000. Si une limite supérieure au maximum est spécifiée, le maximum est utilisé. Ce même maximum s'applique au Méthode fetch () de la classe GqlQuery.

Remarque: comme le paramètre offset pour la méthode fetch (), un OFFSET dans un GQL La chaîne de requête ne réduit pas le nombre d'entités extraites du fichier magasin de données. Cela n'affecte que lequel les résultats sont retournés par la fonction fetch () méthode. Une requête avec un décalage a caractéristiques de performance qui correspondre linéairement avec le décalage Taille.

De http://code.google.com/appengine/docs/datastore/queryclass.html

Les arguments limite et offset contrôlent combien de résultats sont extraits du datastore, et combien sont retournés par la méthode fetch ():

  • Le magasin de données récupère les résultats offset + limite dans l'application. Les premiers résultats de décalage sont pas ignorés par le magasin de données lui-même.

  • La méthode fetch () ignore les premiers résultats de décalage, puis renvoie le reste (limite des résultats).

  • La requête a des caractéristiques de performance qui correspondent linéairement avec le montant du décalage plus la limite.

Qu'est-ce que cela signifie? 

Si vous avez une requête singulière, vous ne pouvez rien demander en dehors de la plage 0-1000. 

L'augmentation du décalage augmentera simplement le 0, donc

LIMIT 1000  OFFSET 0    

Retournera 1000 lignes, 

et 

LIMIT 1000 OFFSET 1000 

Renverra 0 rows, rendant ainsi impossible, avec une syntaxe de requête unique, d'extraire 2000 résultats manuellement ou à l'aide de l'API. 

La seule exception plausible

Est de créer un index numérique sur la table, à savoir: 

 SELECT * FROM Foo  WHERE ID > 0 AND ID < 1000 

 SELECT * FROM Foo WHERE ID >= 1000 AND ID < 2000

Si vos données ou votre requête ne peuvent pas avoir cet identifiant codé en dur 'ID', alors vous êtes pas de chance

14
Kent Fredric

Ce problème de limite de 1K est résolu.

query = MyModel.all()
for doc in query:
    print doc.title

En traitant l'objet de requête comme un élément itérable: l'itérateur récupère les résultats du magasin de données par petits lots, ce qui permet à l'application de cesser d'itérer les résultats pour éviter d'en extraire plus que nécessaire. L'itération s'arrête lorsque tous les résultats correspondant à la requête ont été extraits. Comme avec fetch (), l'interface d'itérateur ne met pas les résultats en cache. La création d'un nouvel itérateur à partir de l'objet Query ré-exécutera la requête.

La taille maximale du lot est 1K. Et vous avez toujours les quotas de magasin de données automatique.

Mais avec le SDK 1.3.1, ils ont introduit des curseurs qui peuvent être sérialisés et enregistrés afin qu’un appel ultérieur puisse commencer la requête là où elle s’était arrêtée pour la dernière fois.

10
Tiger Woods

La limite d'enregistrement de 1000 est une limite stricte dans Google AppEngine.

Cette présentation http://sites.google.com/site/io/building-scalable-web-applications-with-google-app-engine explique comment parcourir efficacement des données à l'aide d'AppEngine.

(Fondamentalement, en utilisant un identifiant numérique comme clé et en spécifiant une clause WHERE sur l'identifiant.)

7
jakber

Récupérer bien que l'API distante a toujours des problèmes quand plus de 1000 enregistrements. Nous avons écrit cette petite fonction pour parcourir une table en morceaux:

def _iterate_table(table, chunk_size = 200):
    offset = 0
    while True:
        results = table.all().order('__key__').fetch(chunk_size+1, offset = offset)
        if not results:
            break
        for result in results[:chunk_size]:
            yield result
        if len(results) < chunk_size+1:
            break
        offset += chunk_size
6
Tzach

nous utilisons quelque chose dans notre classe ModelBase qui est:

@classmethod
def get_all(cls):
  q = cls.all()
  holder = q.fetch(1000)
  result = holder
  while len(holder) == 1000:
    holder = q.with_cursor(q.cursor()).fetch(1000)
    result += holder
  return result

Cela permet de contourner la limite de 1000 requêtes sur chaque modèle sans avoir à y penser. Je suppose qu'une version à clé serait tout aussi facile à implémenter.

3
Gabriel
entities = []
for entity in Entity.all():
    entities.append(entity)

Aussi simple que cela. Notez qu'il existe un RPC créé pour chaque entité qui est beaucoup plus lent que l'extraction en morceaux. Donc, si vous êtes préoccupé par les performances, procédez comme suit:

Si vous avez moins de 1 million d'articles:

entities = Entity.all().fetch(999999)

Sinon, utilisez un curseur.

Il convient également de noter que:

Entity.all().fetch(Entity.all().count())

renvoie 1000 max et ne doit pas être utilisé.

2
crizCraig
class Count(object):
def getCount(self,cls):
    class Count(object):
def getCount(self,cls):
    """
    Count *all* of the rows (without maxing out at 1000)
    """
    count = 0
    query = cls.all().order('__key__')


    while 1:
        current_count = query.count()
        count += current_count
        if current_count == 0:
            break

        last_key = query.fetch(1, current_count-1)[0].key()
        query = query.filter('__key__ > ', last_key)

    return count
2
fun_vit

JJG: votre solution ci-dessus est géniale, sauf qu'elle provoque une boucle infinie si vous avez 0 enregistrements (Je l'ai découvert en testant certains de mes rapports localement).

J'ai modifié le début de la boucle while pour ressembler à ceci:

while count % 1000 == 0:
    current_count = query.count()
    if current_count == 0:
        break
1
mhawthorne

Pour ajouter le contenu des deux requêtes ensemble:

list1 = first query
list2 = second query
list1 += list2

La liste 1 contient maintenant les 2000 résultats.

0
Tom Leys

Ceci est proche de la solution fournie par Gabriel, mais ne récupère pas les résultats, il les compte:

count = 0
q = YourEntityClass.all().filter('myval = ', 2)
countBatch = q.count()
while countBatch > 0:
    count += countBatch
    countBatch = q.with_cursor(q.cursor()).count()

logging.info('Count=%d' % count)

Fonctionne parfaitement pour mes requêtes, et rapide aussi (1,1 seconde pour compter 67 000 entités)

Notez que la requête ne doit pas être un filtre d'inégalité ou un ensemble, sinon le curseur ne fonctionnera pas et vous obtiendrez cette exception:

AssertionError: aucun curseur disponible pour une requête multiple (requêtes utilisant les opérateurs "IN" ou "! =")

0
Timothy Tripp

Si vous utilisez NDB:

@staticmethod
def _iterate_table(table, chunk_size=200):
    offset = 0
    while True:
        results = table.query().order(table.key).fetch(chunk_size + 1, offset=offset)
        if not results:
            break
        for result in results[:chunk_size]:
            yield result
        if len(results) < chunk_size + 1:
            break
        offset += chunk_size
0
Oded Breiner

La solution proposée ne fonctionne que si les entrées sont triées par clé ... Si vous triez d'abord par une autre colonne, vous devez toujours utiliser une clause limit (offset, count), la limitation de 1 000 entrées s'appliquant toujours. Il en va de même si vous utilisez deux requêtes: une pour récupérer des index (avec des conditions et un tri) et une autre en utilisant where où index in () avec un sous-ensemble d'index du premier résultat, car la première demande ne peut pas renvoyer plus de 1000 clés? (La section Google Requêtes sur les clés n'indique pas clairement si nous devons trier par clé pour supprimer la limitation de 1 000 résultats)

0
cjed