2012-04-24 32 views
38

Tôi cố gắng để lặp qua vòng lặp này:MongoDB con trỏ id không hợp lệ lỗi

for doc in coll.find() 

tôi nhận được lỗi sau vào thứ 100.000 cộng với kỷ lục.

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 

lỗi này có ý nghĩa gì?

Trả lời

36

Có thể con trỏ của bạn đã hết thời gian trên máy chủ. Để xem nếu điều này là vấn đề, cố gắng thiết lập timeout = false`:

for doc in coll.find(timeout=False) 

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

Nếu nó là một vấn đề thời gian chờ một giải pháp khả thi là để thiết lập batch_size (s câu trả lời khác.).

+0

sẽ thử ngay bây giờ. cảm ơn! – codious

+2

Câu hỏi thường gặp cho thấy bạn có chính xác: http://api.mongodb.org/python/current/faq.html#what-does-operationfailure-cursor-id-not-valid-at-server-mean –

+0

im tại Kỷ lục thứ 50,000. chờ đợi để xem nếu im thông qua :) – codious

24

Đặt timeout=False là thực tiễn rất tồi. Cách tốt hơn để loại bỏ ngoại lệ thời gian chờ id con trỏ là ước tính số lượng tài liệu mà vòng lặp của bạn có thể xử lý trong vòng 10 phút và đưa ra kích thước hàng loạt bảo thủ. Bằng cách này, máy khách MongoDB (trong trường hợp này, PyMongo) sẽ phải truy vấn máy chủ một lần trong một thời gian bất cứ khi nào các tài liệu trong lô trước được sử dụng hết. Điều này sẽ giữ cho con trỏ hoạt động trên máy chủ và bạn sẽ vẫn được bảo vệ bởi bảo vệ thời gian chờ 10 phút.

Đây là cách bạn thiết lập kích thước hàng loạt cho một con trỏ:

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

điểm thú vị. cảm ơn rất nhiều! – codious

+0

Tôi đồng ý, điều này nghe có vẻ như giải pháp tốt hơn –

32
  • Thiết lập timeout=False là nguy hiểm và không bao giờ nên được sử dụng, bởi vì kết nối để con trỏ có thể vẫn mở cho thời gian không giới hạn, mà sẽ ảnh hưởng đến hiệu năng hệ thống. The docs specifically reference cần phải đóng con trỏ theo cách thủ công.
  • Đặt số batch_size thành một số nhỏ sẽ hoạt động nhưng tạo ra sự cố về độ trễ lớn vì chúng tôi cần truy cập vào DB thường xuyên hơn mức cần thiết.
    Ví dụ:
    5 triệu tài liệu với một lô nhỏ sẽ mất hàng giờ để truy xuất cùng một dữ liệu mà lô_số mặc định sẽ trả về sau vài phút.

Trong giải pháp của tôi nó là bắt buộc để sử dụng loại trên con trỏ:

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

Đây là một giải pháp tốt đẹp, mặc dù nếu bạn có một vài triệu mục và không có "thời gian hoặc tham số tuần tự khác" thì không thực tế. Không thể tin rằng không có giải pháp tự giải quyết. –

+0

Chỉ cần làm rõ. Giải pháp này (hoặc là một trong những lô) không đảm bảo lặp lại tất cả các tài liệu chỉ một lần. Một số tài liệu có thể mang lại nhiều hơn một lần hoặc bỏ qua nếu cơ sở dữ liệu được cập nhật giữa các truy vấn. Đối với thống kê đề xuất này thường không phải là một vấn đề tuy nhiên nếu bạn cần chính xác này có thể là một vấn đề trong một số trường hợp. –

0

Bạn cũng có thể buộc đánh giá bằng cách sử dụng:

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

Làm cách nào? Tại sao? Kỹ lưỡng. – peterh

+0

@peterh Câu hỏi đặt ra là khắc phục vấn đề thời gian chờ của con trỏ, không phải giải thích cách con trỏ và lô hoạt động. Tôi đồng ý một lời giải thích chi tiết hơn sẽ là tuyệt vời, nhưng câu trả lời này vẫn hợp lệ, khi chuyển đổi 'con trỏ' thành' danh sách' sẽ buộc nó lấy tất cả các lô và đóng, rất có thể trước thời gian hết hạn mặc định là 10 phút. – Danziger

0

bạn nên chọn mức thấp giá trị của batch_size để khắc phục sự cố:

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

xem như sau answer

Các vấn đề liên quan