Question

Comment puis-je extraire plus de 1000 enregistrements du magasin de données et les mettre tous dans une seule liste à transmettre à django?

Était-ce utile?

La solution

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

À partir du journal des modifications:

  

Les résultats des requêtes de nombre () de banques de données et les décalages de toutes les requêtes de banque de données ne sont plus limités à 1 000 .

Autres conseils

Juste pour l'enregistrement - la limite d'extraction de 1 000 entrées a maintenant disparu:

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

Citation:

  

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 au cours des derniers mois,   nous sommes maintenant assez confiants pour enlever   la limite maximale de résultat tout à fait.   Si vous faites un aller chercher,   itérer, ou en utilisant un curseur, il y a   pas de limite sur le nombre de résultats.

App Engine vous offre un moyen pratique de "pagination". à travers les résultats par 1000 en commandant 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 à 1 000 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 ne soient nécessaires.

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

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

À chaque fois que cela apparaît comme une limitation, je me demande toujours " pourquoi avez-vous besoin de plus de 1 000 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 = Je ne le savais que récemment, car je n'avais jamais pris le temps de cliquer sur la 100e page des résultats de recherche d'une requête.

Si vous renvoyez plus de 1 000 résultats à l'utilisateur, je pense que le problème est plus important que le fait que le magasin de données ne vous le permet pas.

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 envoi, et de les sauvegarder.

Vous ne pouvez pas.

Une partie de la FAQ indique qu'il est impossible d'accéder au-delà de la ligne 1000 d'une requête, ce qui augmente le nombre d'option " OFFSET " entraînera simplement un ensemble de résultats plus court,

c'est-à-dire: OFFSET 999 - > 1 résultat revient.

Sur 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   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 c'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 une   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 retourner 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 le délai d'attente,   mais la limite est en place pour conserver   ressources sur le magasin de données.

De http://code.google.com/appengine/docs/ magasin de données / 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 à la   fetch () de la classe GqlQuery.

     

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

De http://code.google.com/appengine/docs/ magasin de données / queryclass.html

  

Le contrôle des arguments limit et offset   combien de résultats sont extraits du   magasin de données, 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 ne sont pas ignorés par le magasin de données lui-même.

  •   
  • La méthode fetch () ignore les résultats du premier décalage, puis renvoie le reste (résultats limites).

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

  •   

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    

Renverra 1000 lignes,

et

LIMIT 1000 OFFSET 1000 

Renverra 0 lignes , 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, par exemple:

 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', vous êtes à court de chance

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’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 de requête ré-exécutera la requête.

La taille maximale du lot est 1K. Et vous avez toujours les quotas de banque 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.

La limite d'enregistrement de 1 000 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 utiliser des pages de données de manière efficace à l'aide de AppEngine.

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

La récupération de l'API distante a toujours des problèmes lorsque plus de 1000 enregistrements sont enregistrés. Nous avons écrit cette fonction minuscule 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

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 aussi simple à mettre en œuvre.

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
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. Par conséquent, si les performances vous préoccupent, procédez comme suit:

Si vous avez moins d'un million d'éléments:

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é.

JJG: votre solution ci-dessus est géniale, sauf qu'elle provoque une boucle infinie si vous avez 0 enregistrements. (J'ai découvert cela 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

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.

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)

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 des opérateurs "IN" ou "!! =")

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top