【问题标题】:mongodb cursor id not valid errormongodb游标id无效错误
【发布时间】:2012-05-05 02:46:53
【问题描述】:

我正在尝试遍历这个循环:

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

这个错误是什么意思?

【问题讨论】:

标签: python mongodb


【解决方案1】:

您应该选择较低的 batch_size 值来解决问题:

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

查看以下answer

【讨论】:

    【解决方案2】:
    • 设置timeout=False 是危险的,不应该使用,因为与游标的连接可以无限期保持打开状态,这会影响系统性能。 The docs specifically reference需要手动关闭光标。
    • batch_size 设置为较小的数字会起作用,但会产生很大的延迟问题,因为我们需要比需要更频繁地访问数据库。
      例如:
      小批量的 500 万份文档需要数小时才能检索 与默认 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
    

    【讨论】:

    • 这是一个不错的解决方案,尽管如果您有几百万个条目并且没有“时间或其他顺序参数”,这是不切实际的。不敢相信没有自我解决方案。
    • 只是为了说清楚。该解决方案(无论是批次解决方案)都不能确保只对所有文档进行一次迭代。如果数据库在查询之间更新,某些文档可能会产生多次或跳过。对于统计建议,这通常不是问题,但是如果您需要精确性,在某些情况下这可能是一个问题。
    • "timeout=False 是危险的,永远不应该使用"这是不正确的 - 如果我有一个脚本可以逐个迭代集合元素,并且每次我花费 5s-15min 的时间,那么我应该使用这个选项。之后没有光标残留的风险,因为它会在脚本结束时与集合一起被销毁。
    • @MaciejUrbański 根据 Mongo 2.4/2.6 文档,这是真的。此参数已更改,即使是名称,也可能是功能。这个问题没有 Mongo 版本的标签,所以这有点令人困惑。无论如何,如果您打开许多游标并忘记关闭它们,由于潜在的高内存使用率,保持游标打开是危险的。将此选项视为高级用户功能,这通常不是您想要做的事情 - 尽管总是有例外。感谢您的反馈:)
    【解决方案3】:

    您还可以使用以下命令强制评估:

    for doc in list(coll.find())
    

    【讨论】:

    • @peterh 问题是关于修复游标超时问题,而不是解释游标和批处理如何工作。我同意更详细的解释会很好,但这个答案仍然有效,因为将 cursor 转换为 list 将强制它检索所有批次并关闭,很可能在 10 分钟默认到期时间之前关闭。跨度>
    【解决方案4】:

    也许您的光标在服务器上超时。要查看这是否是问题所在,请尝试设置 timeout=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(其他答案)。

    【讨论】:

    • 常见问题解答建议您正确:api.mongodb.org/python/current/…
    • 我在第 50,000 条记录。等着看我是否通过:)
    • 请注意,这会消耗服务器上的内存,直到您明确关闭它。见mongodb.org/display/DOCS/…
    • @CraigYounkins 如果我错了,请纠正我,但是对于 pymongo,我相信游标对象在被垃圾收集时会关闭,所以除非有网络之类的东西,否则这不是问题失败(所以 pymongo 无法告诉服务器关闭它)。
    • 我只是在 pymongo 源代码中查找它:是的,当光标被垃圾收集时它确实会关闭。网络故障和损坏的垃圾收集(例如:python 析构函数中的循环引用)可能会阻止它工作。
    【解决方案5】:

    设置timeout=False 是一种非常糟糕的做法。摆脱 cursor id 超时异常的更好方法是估计您的循环在 10 分钟内可以处理多少个文档,并得出一个保守的批量大小。这样,只要前一批中的文档用完,MongoDB 客户端(在本例中为 PyMongo)就必须不时地查询服务器。这将使光标在服务器上保持活动状态,并且您仍将受到 10 分钟超时保护的保护。

    以下是设置游标批量大小的方法:

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

    【讨论】:

    • 我同意,这听起来像是更好的解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    相关资源
    最近更新 更多