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

这个错误是什么意思?

2 个评论
这是现有技术,也就是较早的QA。
python
mongodb
codious
codious
发布于 2012-04-24
5 个回答
Reto Aebersold
Reto Aebersold
发布于 2015-11-28
已采纳
0 人赞同

也许你的游标在服务器上超时了。看看这是否是问题所在,试着设置timeout=False`。

for doc in coll.find(timeout=False)

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

如果是超时问题,一个可能的解决方案是设置batch_size(s.其他答案)。

常见问题表明,你的说法是正确的。api.mongodb.org/python/current/...
我在第50,000个记录上。等着看我是否通过。)
请注意,这将消耗服务器的内存,直到你明确关闭它。见mongodb.org/display/DOCS/...
@CraigYounkins 如果我错了,请纠正我,但在pymongo中,我相信游标对象在被垃圾回收时是被关闭的,所以这不是一个问题,除非有类似网络故障的情况(所以pymongo不能告诉服务器关闭它)。
我刚刚在pymongo的源代码中查看了它:是的,当游标被垃圾回收时,它确实被关闭了。不过,网络故障和破损的垃圾收集(例如:Python析构器中的循环引用)可能会阻止它工作。
Oran
Oran
发布于 2015-11-28
0 人赞同
  • Setting the timeout=False is dangerous and should never be used, because the connection to the cursor can remain open for unlimited time, which will affect system performance. The docs specifically reference the need to manually close the cursor.
  • Setting the batch_size to a small number will work, but creates a big latency issue, because we need to access the DB more often than needed.
    For example:
    5M docs with a small batch will take hours to retrieve the same data that a default batch_size returns in several minutes.
  • 在我的解决方案中,必须使用sort on the 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 )
            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
        
    这是一个不错的解决方案,尽管如果你有几百万个条目,而且没有 "时间或其他顺序参数",那就不切实际了。不敢相信竟然没有脱离自我的解决方案。
    我只是想说清楚。这个解决方案(或批处理方案)并不确保只迭代一次所有的文件。如果数据库在两次查询之间被更新,一些文件可能会被产生不止一次或被跳过。对于统计建议来说,这通常不是一个问题,但是如果你需要精确性,这在某些情况下可能是一个问题。
    "timeout=False是很危险的,不应该使用",这是不正确的--如果我有一个脚本,逐个遍历集合元素,并且在每个元素上花费5s-15min的时间,那么我应该使用这个选项。因为游标会在脚本结束时和集合一起被销毁,所以不会有游标残留的风险。
    Oran
    @MaciejUrbański 根据Mongo 2.4/2.6文档,这是真的。这个参数被改变了,甚至在名称上,可能在功能上也有改变。这个问题没有标记到Mongo的版本,所以这有点令人困惑。不管怎么说,保持游标开放是很危险的,因为潜在的高内存占用,如果你打开许多游标而忘记关闭它们。把这个选项看作是高级用户功能,通常不是你想做的事情--尽管总是有例外。谢谢你的反馈 :)
    jiehanzheng
    jiehanzheng
    发布于 2015-11-28
    0 人赞同

    设置timeout=False是一个非常糟糕的做法。 摆脱游标id超时异常的一个更好的方法是估计你的循环能在10分钟内处理多少文档,并得出一个保守的批次大小。 这样一来,MongoDB客户端(在本例中是PyMongo)将不得不在前一个批次的文档用完后,偶尔查询一下服务器。 这将使游标在服务器上保持活跃,而且你仍然会被10分钟的超时保护所覆盖。

    下面是你如何为游标设置批量大小。

    for doc in coll.find().batch_size(30):
        do_time_consuming_things()
        
    我同意,这听起来是更好的解决方案
    HISI
    HISI
    发布于 2015-11-28
    0 人赞同

    你应该选择一个低值的 batch_size 来解决这个问题。

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

    see the following 答案