Неверная ошибка курсора mongodb
Я пытаюсь выполнить итерацию через этот цикл:
for doc in coll.find()
Я получаю следующую ошибку на 100 000-й плюс.
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
что означает эта ошибка?
Ответы
Ответ 1
Возможно, ваш указатель на сервере отключен. Чтобы убедиться, что это проблема, попробуйте установить таймаут = False`:
for doc in coll.find(timeout=False)
См. http://api.mongodb.org/python/1.6/api/pymongo/collection.html#pymongo.collection.Collection.find
Если это была проблема с таймаутом, одним из возможных решений является установка ответов batch_size
(s. other).
Ответ 2
- Установка
timeout=False
опасна и никогда не должна использоваться, поскольку соединение с курсором может оставаться открытым неограниченное время, что скажется на производительности системы. Документы специально указывают на необходимость вручную закрыть курсор.
- Настройка
batch_size
на небольшое число будет работать, но создает большую проблему с задержкой, потому что нам нужно чаще обращаться к БД, чем нужно.
Например:
Документы 5M с небольшой партией будут занимать часы для извлечения
те же данные, которые по умолчанию batch_size возвращает за несколько минут.
В моем решении обязательно использовать sort в курсоре:
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
Ответ 3
Настройка timeout=False
- очень плохая практика. Лучший способ избавиться от исключения тайм-аута идентификатора курсора - оценить количество документов, которые ваш цикл может обрабатывать в течение 10 минут, и придумать консервативный размер партии. Таким образом, клиент MongoDB (в данном случае, PyMongo) будет запрашивать сервер один раз в то время, когда были израсходованы документы предыдущей партии. Это будет держать курсор активным на сервере, и вы все равно будете защищены 10-минутной тайм-аутом.
Вот как вы устанавливаете размер партии для курсора:
for doc in coll.find().batch_size(30):
do_time_consuming_things()
Ответ 4
Вы также можете принудительно выполнить оценку, используя:
for doc in list(coll.find())
Ответ 5
вы должны выбрать низкое значение batch_size, чтобы исправить проблему:
col.find({}).batch_size(10)
см. следующий ответ