Domanda

Come posso recuperare più di 1000 record dall'archivio dati e metterli tutti in un unico elenco per passare a django?

È stato utile?

Soluzione

A partire dalla versione 1.3.6 (rilasciata il 17 agosto 2010), PUOI

Dal log delle modifiche:

  

I risultati delle query count () del datastore e gli offset per tutte le query del datastore non sono più limitati a 1000 .

Altri suggerimenti

Solo per la cronaca - il limite di recupero di 1000 voci è ora sparito:

http: //googleappengine.blogspot. com / 2010/02 / app-motore-sdk-131-incluso-major.html

Quotazione:

  

Non ci sono più 1000 limiti di risultati   a destra: con l'aggiunta di Cursori e   il culmine di molti più piccoli   Stabilità e prestazioni del datastore   miglioramenti negli ultimi mesi,   ora siamo abbastanza fiduciosi da rimuovere   il limite massimo di risultati del tutto.   Che tu stia facendo un recupero,   iterando o usando un cursore, c'è   nessun limite al numero di risultati.

App Engine ti offre un buon modo per " paginare " attraverso i risultati per 1000 ordinando i tasti e usando l'ultimo tasto come offset successivo. Forniscono anche un codice di esempio qui:

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

Sebbene il loro esempio distribuisca le query su molte richieste, è possibile modificare le dimensioni della pagina da 20 a 1000 ed eseguire query in un ciclo, combinando i queryset. Inoltre, è possibile utilizzare itertools per collegare le query senza valutarle prima che siano necessarie.

Ad esempio, per contare quante righe oltre 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

Ogni volta che si presenta come una limitazione, mi chiedo sempre " perché hai bisogno di più di 1.000 risultati? " Sapevi che Google non fornisce più di 1.000 risultati? Prova questa ricerca: http://www.google.ca/search?hl=en&client=firefox-a&rls=org.mozilla:en-US:official&hs=qhu&q=1000+results&start = 1000 & amp; sa = N Non lo sapevo fino a poco tempo fa, perché non avevo mai avuto il tempo di fare clic sulla 100a pagina dei risultati di ricerca su una query.

Se in realtà stai restituendo all'utente più di 1.000 risultati, penso che ci sia un problema più grande del fatto che l'archivio dati non ti consente di farlo.

Una possibile (legittima) ragione per cui sono necessari molti risultati è se si eseguisse una grande operazione sui dati e si presentasse un riepilogo (ad esempio, qual è la media di tutti questi dati). La soluzione a questo problema (di cui si parla nella discussione I / O di Google) è calcolare i dati di riepilogo al volo, non appena arrivano, e salvarli.

Non puoi.

Parte delle FAQ afferma che non è possibile accedere oltre la riga 1000 di una query, aumentando il valore "OFFSET" si tradurrà semplicemente in un set di risultati più breve,

ie: OFFSET 999 - > 1 risultato ritorna.

Da Wikipedia:

  

App Engine limita il numero massimo di righe   restituito da un'entità arriva a 1000   righe per chiamata archivio dati. La maggior parte del web   le applicazioni di database utilizzano il paging e   memorizzazione nella cache, e quindi non richiedono questo   molti dati contemporaneamente, quindi questo è un   non problematico nella maggior parte degli scenari. [citazione   necessario] Se un'applicazione ha bisogno di più   di 1.000 record per operazione   può utilizzare il proprio software lato client   o una pagina Ajax per eseguire un   operazione su un numero illimitato di   righe.

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

  

Un altro esempio di limite di servizio è   il numero di risultati restituiti da a   query. Una query può restituire al massimo   1.000 risultati. Domande che lo farebbero   restituisce più risultati restituisce solo il   massimo. In questo caso, una richiesta che   esegue una query del genere non è probabile   restituire una richiesta prima del timeout,   ma il limite è in atto per conservare   risorse sull'archivio dati.

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

  

Nota: una clausola LIMIT ha un massimo di   1000. Se viene specificato un limite superiore al massimo, il massimo è   Usato. Lo stesso valore massimo si applica a   Metodo fetch () della classe GqlQuery.

     

Nota: come il parametro offset per   il metodo fetch (), un OFFSET in un GQL   la stringa di query non riduce il valore   numero di entità recuperate da   archivio dati. Colpisce solo quale   i risultati vengono restituiti da fetch ()   metodo. Una query con un offset ha   caratteristiche prestazionali che   corrisponde linearmente con l'offset   dimensioni.

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

  

Il controllo degli argomenti limite e offset   quanti risultati vengono recuperati da   archivio dati e quanti vengono restituiti   con il metodo fetch ():

     
      
  • L'archivio dati recupera i risultati offset + limite nell'applicazione. I primi risultati dell'offset sono non ignorati dal datastore stesso.

  •   
  • Il metodo fetch () salta i primi risultati di offset, quindi restituisce il resto (limita i risultati).

  •   
  • La query ha caratteristiche prestazionali corrispondenti   linearmente con l'importo della compensazione più il limite.

  •   

Ciò che significa è

Se hai una query singolare, non c'è modo di richiedere qualcosa al di fuori dell'intervallo 0-1000.

L'offset crescente aumenterà solo lo 0, quindi

LIMIT 1000  OFFSET 0    

Restituirà 1000 righe,

e

LIMIT 1000 OFFSET 1000 

Restituirà 0 righe , quindi, rendendo impossibile, con una singola sintassi della query, recuperare 2000 risultati manualmente o usando l'API.

L'unica eccezione plausibile

Serve per creare un indice numerico sulla tabella, ovvero:

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

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

Se i tuoi dati o query non possono avere questo identificatore hardcoded "ID", allora sei sfortunato

Questo problema con il limite di 1K è stato risolto.

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

Considerando l'oggetto Query come iterabile: l'iteratore recupera i risultati dall'archivio dati in piccoli lotti, consentendo all'app di interrompere l'iterazione sui risultati per evitare di recuperare più del necessario. L'iterazione si interrompe quando tutti i risultati che corrispondono alla query sono stati recuperati. Come con fetch (), l'interfaccia iteratore non memorizza nella cache i risultati, quindi la creazione di un nuovo iteratore dall'oggetto Query eseguirà nuovamente la query.

La dimensione massima del batch è 1K. E hai anche le quote automatiche di Datastore.

Ma con il piano 1.3.1 SDK, hanno introdotto cursori che possono essere serializzati e salvati in modo che una futura chiamata possa iniziare la query da dove era stata interrotta l'ultima volta.

Il limite dei 1000 record è un limite rigido in Google AppEngine.

Questa presentazione http: / /sites.google.com/site/io/building-scalable-web-applications-with-google-app-engine spiega come sfogliare in modo efficiente i dati usando AppEngine.

(Fondamentalmente usando un id numerico come chiave e specificando una clausola WHERE sull'id.)

Il recupero anche se l'API remoto ha ancora problemi quando più di 1000 record. Abbiamo scritto questa minuscola funzione per scorrere su una tabella in blocchi:

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

stiamo usando qualcosa nella nostra classe ModelBase che è:

@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

Ciò aggira il limite di 1000 query su ogni modello senza pensarci. Suppongo che una versione di chiavi sarebbe altrettanto facile da implementare.

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)

Semplice come quello. Si noti che esiste un RPC creato per ogni entità che è molto più lento del recupero in blocchi. Quindi, se sei preoccupato per le prestazioni, procedi come segue:

Se hai meno di 1 milione di articoli:

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

Altrimenti, usa un cursore.

Va ??anche notato che:

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

restituisce 1000 max e non deve essere utilizzato.

JJG: la tua soluzione sopra è fantastica, tranne per il fatto che provoca un ciclo infinito se hai 0 record. (L'ho scoperto mentre provavo alcuni dei miei rapporti localmente).

Ho modificato l'inizio del ciclo while in questo modo:

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

Per aggiungere insieme il contenuto delle due query:

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

L'elenco 1 ora contiene tutti i 2000 risultati.

La soluzione proposta funziona solo se le voci sono ordinate per chiave ... Se si ordina prima per un'altra colonna, è comunque necessario utilizzare una clausola di limite (offset, conteggio), quindi la limitazione di 1000 voci si applica comunque. È lo stesso se usi due richieste: una per recuperare gli indici (con condizioni e ordinamento) e un'altra usando dove index in () con un sottoinsieme di indici dal primo risultato, poiché la prima richiesta non può restituire più di 1000 chiavi? (La sezione Query on Keys di Google non indica chiaramente se dobbiamo ordinare per chiave per rimuovere la limitazione dei 1000 risultati)

Questo è vicino alla soluzione fornita da Gabriel, ma non recupera i risultati ma li conta semplicemente:

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)

Funziona perfettamente per le mie query e anche veloce (1,1 secondi per contare 67.000 entità)

Nota che la query non deve essere un filtro di disuguaglianza o un set o il cursore non funzionerà e otterrai questa eccezione:

  

AssertionError: nessun cursore disponibile per una MultiQuery (query che utilizzano gli operatori " IN " o "! = ")

Se si utilizza 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top