2016-09-21 7 views
3

У меня есть коллекция документов 500K +, которая хранится на одном монголе узла. Время от времени мой pymongo cursor.find() терпит неудачу, когда он истекает.Использование генератора для итерации по большой коллекции в Mongo

Хотя я мог установить find, чтобы игнорировать таймаут, мне не нравится этот подход. Вместо этого я попробовал генератор (адаптировано из this ответа и this ссылки):

def mongo_iterator(self, cursor, limit=1000): 
     skip = 0 
     while True: 
      results = cursor.find({}).sort("signature", 1).skip(skip).limit(limit) 

      try: 
       results.next() 

      except StopIteration: 
       break 

      for result in results: 
       yield result 

      skip += limit 

Я тогда этот метод вызывается с помощью:

ref_results_iter = self.mongo_iterator(cursor=latest_rents_refs, limit=50000) 
for ref in ref_results_iter: 
    results_latest1.append(ref) 

Проблемы: Моего итератор не возвращает то же число Результаты. Проблема в том, что next() продвигает курсор. Поэтому для каждого звонка я теряю один элемент ...

Вопрос: Есть ли способ адаптировать этот код, чтобы я мог проверить, существует ли следующее? Pymongo 3x не предоставляет hasNext() и 'alive' check is not guaranteed, чтобы вернуть false.

+0

'0 to 1000' равно' [0,1,2,3 ......, 999] ', следующий старт -' 1000, но вы потеряете один (возможно, last_one). Поэтому 'номер индекса никогда не равен length_number'. – dsgdfg

+0

Будет ли работать «first_result_in_batch = results.next()», таким образом, захватив элемент, который вы сейчас отбрасываете (если есть)? Затем вы должны поставить 'yield first_result_in_batch' над циклом for, таким образом предоставив этот элемент вызывающему в правильном порядке. (Я не знаю MongoDB, так что, может быть, я чего-то не хватает.) –

ответ

1

Почему бы не использовать

for result in results: 
    yield result 

для цикла должен обрабатывать StopIteration для вас.

+0

Он останавливается, но затем мне нужно знать и обрабатывать итерации и пропуски снаружи (например, забрать первые 10 000, обработать, выбрать следующий 10 000 процессов и т. Д.). Как я уже сказал, проблема заключается в «остановке» без потери данных. – goggelj

+0

это не ответ! Уже «результат» получил 1000 элементов. – dsgdfg

+0

@dsgdfg вам не хватает всего. Я согласен, что у вас уже есть 1000, но из-за следующего() вы просто уронили один. Я предполагаю, что единственный способ - выполнить «счет» и взять логику пропуска/ограничения из итератора. – goggelj

1

Метод .find() принимает дополнительные аргументы ключевых слов. Одним из них является no_cursor_timeout, который необходимо установить в True

cursor = collection.find({}, no_cursor_timeout=True) 

Вам не нужно писать свою собственную функцию генератора. Метод find() возвращает объект типа генератора.

+0

Установка таймаута в False приводит к тому, что мне приходится отказываться от VM ... он просто зависает. – goggelj