2016-11-04 78 views
0

我需要從mongo(v3.2.10)集合(使用Pymongo 3.3.0)中獲取大量(例如1億)文檔並遍歷它們。迭代將需要幾天時間,並且由於超時遊標,我經常遇到異常。pymongo光標'touch'以避免超時

在我的情況下,我需要睡眠不可預測的時間量迭代。因此,例如,我可能需要: - 獲取10個文件 - 睡眠1秒 - 取1000個文檔 - 睡4小時 - 取1號文件 等

我知道我可以:

  • 完全禁用超時,但我想避免這種情況,如果可能的話,因爲如果我的代碼完全停止運行,我很高興爲它清除光標
  • 減少我的光標的batch_size,但這不會幫助如果例如我需要睡4個小時,如上例所示

這似乎是一個很好的解決方案,它將觸摸光標以保持活動狀態。因此,例如,我會在較短的時間間隔內長時間休息,並在每個間隔之間觸摸光標。

我沒有看到通過pymongo做到這一點的方法,但我想知道是否有人知道是否有可能。

回答

2

當然,這是不可能的,你想要的是功能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 ... 

此代碼遍歷光標完全,所以它不超時,然後處理1000個文檔,然後重複下一個1000

二理念:用a very long cursor timeout配置您的服務器:

mongod --setParameter cursorTimeoutMillis=21600000 # 6 hrs 

第三個想法:你可以更多一些,雖然不是完全一定的,你會在一個使用它關閉不超時光標聲明:

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.... 
+0

是在可能的情況,但對我來說,我有一些非常複雜的查詢,我不想每次都用新的查詢,以重新啓動模式是有用的 - 我想保持一個遊標在服務器上以某種方式打開 – nonagon

+0

我已更新我的答案。你問「如果有人知道是否有可能」,我已經明確地回答了。 =) –

+0

你的答案確實完整,所以我接受它。我想我只是有一個堆棧溢出寵物peeve,因爲每次我問一個焦點問題「我該怎麼做X」我總是得到一百萬憤怒的答覆說:「你不想做X你應該做Y或Z」時當然Y或Z是不可能的在我的情況下,但它會解釋太多的上下文:)。無論如何謝謝你的答案,這確實是相當有幫助的! – nonagon