PyMongo - итерация курсора - PullRequest
21 голосов
/ 13 июля 2011

Я недавно начал тестировать MongoDB через оболочку и через PyMongo.Я заметил, что возврат курсора и попытка его перебрать кажется узким местом в реальной итерации.Есть ли способ вернуть более одного документа во время итерации?

Псевдокод:

for line in file:
    value = line[a:b]
    cursor = collection.find({"field": value})
    for entry in cursor:
        (deal with single entry each time)

Я надеюсь сделать что-то вроде этого:

for line in file
    value = line[a:b]
    cursor = collection.find({"field": value})
    for all_entries in cursor:
        (deal with all entries at once rather than iterate each time)

Я пытался использовать batch_size () в соответствии с этим вопросом и полностью изменять значение до 1000000, но, похоже, это не дает никакого эффекта (или я делаю это неправильно).

Любая помощь очень ценится.Пожалуйста, будьте осторожны с этим новичком в Монго!

--- EDIT ---

Спасибо, Калеб.Я думаю, вы указали на то, что я действительно пытался спросить, а именно: есть ли способ выполнить команду типа collection.findAll() или, может быть, cursor.fetchAll(), как в случае с модулем cx_Oracle?Проблема не в хранении данных, а в их извлечении из БД Mongo как можно быстрее.

Насколько я могу судить, скорость, с которой мне возвращаются данные, определяется моей сетью, посколькуМонго должен выбирать каждую запись по одному, верно?

Ответы [ 4 ]

16 голосов
/ 13 июля 2011

Рассматривали ли вы такой подход, как:

for line in file
  value = line[a:b]
  cursor = collection.find({"field": value})
  entries = cursor[:] # or pull them out with a loop or comprehension -- just get all the docs
  # then process entries as a list, either singly or in batch

Альтернативно, что-то вроде:

# same loop start
  entries[value] = cursor[:]
# after the loop, all the cursors are out of scope and closed
for value in entries:
  # process entries[value], either singly or in batch

В основном, если у вас достаточно ОЗУ для хранения наборов результатов, вы должныбыть в состоянии снять их с курсоров и удерживать их перед обработкой.Это вряд ли будет значительно быстрее, но это уменьшит любое замедление, в частности, курсоров, и освободит вас для параллельной обработки данных, если вы настроены для этого.

14 голосов
/ 13 июля 2011

Вы также можете попробовать:

results = list(collection.find({'field':value}))

Это должно загрузить все прямо в оперативную память.

Или это возможно, если ваш file не слишком велик:

values = list()
for line in file:
    values.append(line[a:b])
results = list(collection.find({'field': {'$in': values}}))
2 голосов
/ 17 мая 2013

toArray() может быть решением.Основываясь на документах, он сначала выполняет итерацию по всем курсорам в Mongo и возвращает результаты только один раз в виде массива.

http://docs.mongodb.org/manual/reference/method/cursor.toArray/

Это не похоже на list(coll.find()) или[doc for doc in coll.find()], который извлекает по одному документу в Python за раз и возвращает обратно в Mongo и извлекает следующий курсор.

Однако этот метод не был реализован в pyMongo ... странный

0 голосов
/ 29 апреля 2015

Как упомянуто выше @jmelesky, я всегда использую один и тот же метод. Вот мой пример кода. Для хранения моего курсора twts_result объявим список ниже для копирования. Используйте оперативную память, если можете хранить данные. Это решит проблему срок ожидания курсора , если не требуется обработка и обновление для вашей коллекции, из которой вы получили данные.

Здесь я получаю твиты из коллекции.

twts_result = maindb.economy_geolocation.find({}, {'_id' : False})
print "Tweets for processing -> %d" %(twts_result.count())

tweets_sentiment = []
batch_tweets = []
#Copy the cursor data into list
tweets_collection = list(twts_result[:])
for twt in tweets_collection:
    #do stuff here with **twt** data
...