pymongo 光标“触摸”以避免超时

non*_*gon 1 mongodb pymongo

我需要从 mongo (v3.2.10) 集合(使用 Pymongo 3.3.0)中获取大量(例如 1 亿个)文档并对其进行迭代。迭代需要几天时间,我经常遇到由于超时游标而导致的异常。

在我的情况下,我需要在迭代时睡眠不可预测的时间。例如,我可能需要: - 获取 10 个文档 - 睡眠 1 秒 - 获取 1000 个文档 - 睡眠 4 小时 - 获取 1 个文档等

我知道我可以:

  • 完全禁用超时,但如果可能的话,我想避免这种情况,因为如果我的代码完全停止运行,很高兴为我清理游标
  • 减少我的光标的batch_size,但是如果例如我需要像上面的例子那样睡4个小时,这将无济于事

似乎一个不错的解决方案是“触摸”光标以使其保持活动状态。因此,例如,我会将长时间的睡眠分成较短的间隔,并在每个间隔之间触摸光标。

我没有看到通过 pymongo 做到这一点的方法,但我想知道是否有人确切知道这是否可行。

A. *_*vis 7

当然,这是不可能的,您想要的是未实现的功能SERVER-6036

对于这样一个长时间运行的任务,我建议对索引字段进行查询。例如,如果您的文档都有时间戳“ts”:

documents = list(collection.find().sort('ts').limit(1000))
for doc in documents:
    # ... process doc ...

while True:
    ids = set(doc['_id'] for doc in documents)
    cursor = collection.find({'ts': {'$gte': documents[-1]['ts']}})
    documents = list(cursor.limit(1000).sort('ts'))
    if not documents:
        break  # All done.
    for doc in documents:
        # Avoid overlaps
        if doc['_id'] not in ids:
            # ... process doc ...
Run Code Online (Sandbox Code Playgroud)

这段代码完全迭代游标,所以它不会超时,然后处理 1000 个文档,然后重复下一个 1000。

第二个想法:使用很长的游标超时配置您的服务器:

mongod --setParameter cursorTimeoutMillis=21600000  # 6 hrs
Run Code Online (Sandbox Code Playgroud)

第三个想法:您可以更确定,尽管不是完全确定,您将通过在with语句中使用它来关闭非超时游标:

cursor = collection.find(..., no_cursor_timeout=True)
with cursor:
    # PyMongo will try to kill cursor on server
    # if you leave this block.
    for doc in cursor:
        # do stuff....
Run Code Online (Sandbox Code Playgroud)