2012-04-24 87 views
38

我想通過這個循環迭代:MongoDB的遊標ID無效的錯誤

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 

這個錯誤是什麼意思?

回答

36

也許你的光標超時在服務器上。要查看是否這是問題,嘗試設置超時= 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(一個或多個答案。)。

+0

將立即嘗試。謝謝! – codious 2012-04-24 13:06:24

+2

該常見問題表明您有這個正確的:http://api.mongodb.org/python/current/faq.html#what-does-operationfailure-cursor-id-not-valid-at-server-mean – 2012-04-24 13:10:11

+0

即時在第50,000個記錄。等待看看我是否通過:) – codious 2012-04-24 13:14:53

24

設置timeout=False是一個非常糟糕的做法。擺脫遊標ID超時異常的更好方法是估計循環可以在10分鐘內處理多少個文檔,並提出一個保守的批量大小。這樣,每當上一批中的文檔用完時,MongoDB客戶端(在這種情況下,PyMongo)將不得不一次查詢服務器。這將使光標在服務器上保持活動狀態,並且您仍然可以享受到10分鐘的超時保護。

這裏是你如何設置批量大小光標:

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

有趣的一點。非常感謝! – codious 2013-07-16 11:27:59

+0

我同意,這聽起來像更好的解決方案 – 2013-09-25 12:54:43

32
  • 設置timeout=False是危險的,不應該被使用,因爲遊標的連接可以保持打開無限的時間,這將影響系統性能。 The docs specifically reference需要手動關閉遊標。
  • batch_size設置爲較小的數字將會起作用,但會產生很大的延遲問題,因爲我們需要更頻繁地訪問數據庫。
    例如:
    帶有小批量的5M文檔將花費數小時檢索 與默認batch_size在幾分鐘內返回的相同數據。

在我的解決辦法是強制使用排序上的光標:使用

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

這是一個很好的解決方案,但如果你有幾百萬條目,沒有「時間或其他順序參數」,這是不切實際的。不能相信沒有自我解決的辦法。 – 2014-01-30 08:31:23

+0

只是爲了說清楚。該解決方案(無論是第一批)都不能確保只重複一次所有文檔。如果數據庫在查詢之間更新,某些文檔可能會產生多次或跳過。對於統計建議,這通常不是問題,但是如果您需要正確的話,這在某些情況下可能是個問題。 – 2015-06-23 10:12:35

0

您還可以強制評估:

for doc in list(coll.find()) 
+0

如何?爲什麼?闡述。 – peterh 2015-11-27 18:57:06

+0

@peterh問題是關於解決遊標超時問題,而不是解釋遊標和批處理的工作方式。我同意更詳細的解釋會很好,但是這個答案仍然有效,因爲將'cursor'轉換爲'list'將強制它檢索所有批次並關閉,很可能在10分鐘的默認過期時間之前。 – Danziger 2017-05-30 00:29:19

0

你應該選擇低batch_size的值來解決問題:

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

請參閱以下內容answer