2012-04-24 21 views
38

Estoy tratando de iterar a través de este bucle:mongodb Identificación del cursor no válido de error

for doc in coll.find() 

me sale el siguiente error en el número 100.000, más registro.

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 

¿qué significa este error?

Respuesta

36

Quizás el tiempo de espera del cursor haya expirado en el servidor. Para ver si este es el problema, tratar de establecer el tiempo de espera = false`:

for doc in coll.find(timeout=False) 

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

Si se trata de un problema de tiempo de espera de una posible solución es establecer la batch_size (s otras respuestas.).

+0

intentaremos en este momento. ¡Gracias! – codious

+2

La pregunta frecuente sugiere que tiene esto correcto: http://api.mongodb.org/python/current/faq.html#what-does-operationfailure-cursor-id-not-valid-at-server-mean –

+0

im the Registro 50,000a. esperando ver si estoy :) – codious

24

Configuración timeout=False es una muy mala práctica. Una mejor forma de deshacerse de la excepción de tiempo de espera id de cursor es calcular cuántos documentos puede procesar su bucle en 10 minutos y obtener un tamaño de lote conservador. De esta manera, el cliente MongoDB (en este caso, PyMongo) tendrá que consultar el servidor de vez en cuando cada vez que se agotaron los documentos en el lote anterior. Esto mantendrá el cursor activo en el servidor, y aún estará cubierto por la protección de tiempo de espera de 10 minutos.

Aquí es cómo establecer el tamaño del lote para un cursor:

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

punto interesante. ¡muchas gracias! – codious

+0

Acepto, esto suena como la mejor solución –

32
  • Ajuste del timeout=False es peligroso y no debe usarse nunca, ya que la conexión con el cursor puede permanecer abierta durante un tiempo ilimitado, que se afectar el rendimiento del sistema The docs specifically reference la necesidad de cerrar manualmente el cursor.
  • Configurar el batch_size en un número pequeño funcionará, pero crea un gran problema de latencia, porque necesitamos acceder al DB más a menudo de lo necesario.
    Por ejemplo:
    5 millones de documentos con un pequeño lote tardarán horas en recuperar los mismos datos que un batch_size predeterminado devuelve en varios minutos.

En mi solución es obligatorio el uso de tipo en el cursor:

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

Esta es una buena solución, aunque si tiene unos pocos millones de entradas y no hay "tiempo u otro parámetro secuencial" no es práctico. No puedo creer que no haya una solución propia. –

+0

Solo para dejarlo en claro. Esta solución (ya sea la del lote) no garantiza que se repitan todos los documentos solo una vez. Algún documento podría ceder más de una vez o saltarse si la base de datos se actualiza entre consultas. Para las propuestas estadísticas esto generalmente no es un problema; sin embargo, si necesita exactitud, esto puede ser un problema en algunos casos. –

0

También puede forzar la evaluación mediante el uso de:

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

¿Cómo? ¿Por qué? Elaborar. – peterh

+0

@peterh La pregunta es sobre cómo solucionar el problema del tiempo de espera del cursor, no sobre cómo funcionan los cursores y los lotes. Estoy de acuerdo en que una explicación más detallada sería genial, pero esta respuesta sigue siendo válida, ya que convertir el 'cursor' en' list' lo forzará a recuperar todos los lotes y cerrarlo, muy probablemente antes del tiempo de caducidad predeterminado de 10 minutos. – Danziger

0

usted debe elegir una baja valor de batch_size para solucionar el problema:

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

consulte lo siguiente answer

Cuestiones relacionadas