2012-04-24 14 views
38

sto cercando di scorrere questo ciclo:MongoDB id cursore non errore valido

for doc in coll.find() 

ottengo il seguente errore al 100.000 ° più record.

File "build\bdist.win32\egg\pymongo\cursor.py", line 703, in next 
File "build\bdist.win32\egg\pymongo\cursor.py", line 679, in _refresh 
File "build\bdist.win32\egg\pymongo\cursor.py", line 628, in __send_message 
File "build\bdist.win32\egg\pymongo\helpers.py", line 95, in _unpack_response 
pymongo.errors.OperationFailure: cursor id '1236484850793' not valid at server 

cosa significa questo errore?

risposta

36

Forse il timeout del cursore sul server. Per vedere se questo è il problema, provare a impostare il timeout = FALSE:

for doc in coll.find(timeout=False) 

Vedi http://api.mongodb.org/python/1.6/api/pymongo/collection.html#pymongo.collection.Collection.find

Se fosse un problema di timeout una possibile soluzione è quella di impostare il batch_size (s altre risposte.).

+0

proverà ora. Grazie! – codious

+2

Le FAQ suggeriscono di avere questo corretto: http://api.mongodb.org/python/current/faq.html#what-does-operationfailure-cursor-id-not-valid-at-server-mean –

+0

im at the 50.000 ° record. in attesa di vedere se im thru :) – codious

24

L'impostazione timeout=False è una pessima pratica. Un modo migliore per eliminare l'eccezione di timeout dell'ID del cursore è stimare quanti documenti il ​​ciclo può elaborare entro 10 minuti e ottenere una dimensione batch conservativa. In questo modo, il client MongoDB (in questo caso, PyMongo) dovrà interrogare il server una volta ogni tanto quando i documenti del batch precedente sono stati utilizzati. Ciò manterrà il cursore attivo sul server, e sarai comunque coperto dalla protezione di timeout di 10 minuti.

Ecco come impostare le dimensioni dei lotti per un cursore:

for doc in coll.find().batch_size(30): 
    do_time_consuming_things() 
+0

punto interessante. molte grazie! – codious

+0

Sono d'accordo, questa sembra la soluzione migliore –

32
  • Impostazione del timeout=False è pericoloso e non dovrebbe mai essere utilizzato, perché la connessione al cursore può rimanere aperta per un tempo illimitato, che sarà influire sulle prestazioni del sistema. The docs specifically reference la necessità di chiudere manualmente il cursore.
  • L'impostazione di batch_size su un numero piccolo funzionerà, ma crea un grosso problema di latenza, poiché è necessario accedere al DB più spesso del necessario.
    Ad esempio:
    I documenti 5M con un piccolo batch impiegano ore per recuperare gli stessi dati restituiti da un batch_size predefinito in diversi minuti.

Nella mia soluzione è obbligatorio l'uso di sorta sul cursore:

done = False 
skip = 0 
while not done: 
    cursor = coll.find() 
    cursor.sort(indexed_parameter) # recommended to use time or other sequential parameter. 
    cursor.skip(skip) 
    try: 
     for doc in cursor: 
      skip += 1 
      do_something() 
     done = True 
    except pymongo.errors.OperationFailure, e: 
     msg = e.message 
     if not (msg.startswith("cursor id") and msg.endswith("not valid at server")): 
      raise 
+0

Questa è una bella soluzione, anche se se hai qualche milione di voci e nessun "tempo o altro parametro sequenziale" non è pratico. Non riesco a credere che non ci sia la soluzione per se stessi. –

+0

Giusto per chiarire. Questa soluzione (o quella in batch) non garantisce l'iterazione di tutti i documenti solo una volta. Alcuni documenti potrebbero essere resi più di una volta o saltati se il database viene aggiornato tra le query. Per le proposte statistiche questo di solito non è un problema, tuttavia se avete bisogno di esattezza, questo potrebbe essere un problema in alcuni casi. –

0

è possibile anche forzare la valutazione utilizzando:

for doc in list(coll.find()) 
+0

Come? Perché? Elaborare. – peterh

+0

@peterh La domanda consiste nel risolvere il problema del timeout del cursore, non nello spiegare come funzionano i cursori e i batch. Sono d'accordo che una spiegazione più dettagliata sarebbe ottima, ma questa risposta è ancora valida, poiché convertire il 'cursor' in' list' lo obbligherà a recuperare tutti i batch e chiudere, molto probabilmente prima del tempo di scadenza predefinito di 10 minuti. – Danziger

0

si dovrebbe scegliere una bassa valore di batch_size per risolvere il problema:

col.find({}).batch_size(10) 

vedere il seguente answer

Problemi correlati