PyMongo - итерация курсора
Недавно я начал тестировать 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, но он, похоже, не имеет никакого эффекта (или я делаю это неправильно).
Любая помощь приветствуется. Пожалуйста, будьте спокойны в этом новичке Mongo!
--- EDIT ---
Спасибо, Калеб. Я думаю, вы указали, что я действительно пытался спросить, что это такое: есть ли способ сделать команду типа collection.findAll()
или, может быть, cursor.fetchAll()
, как есть с модулем cx_Oracle? Проблема заключается не в хранении данных, а в извлечении из Mongo DB как можно быстрее.
Насколько я могу судить, скорость, с которой мне возвращаются данные, продиктована моей сетью, так как Mongo должен однократно выбирать каждую запись, исправить?
Ответы
Ответ 1
Рассматривали ли вы такой подход, как:
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
В принципе, до тех пор, пока у вас достаточно ОЗУ для хранения наборов результатов, вы должны убрать их с курсоров и удерживать их перед обработкой. Это вряд ли будет значительно быстрее, но оно смягчит любое замедление в отношении курсоров и позволит вам обрабатывать ваши данные параллельно, если вы настроены для этого.
Ответ 2
Вы также можете попробовать:
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}}))
Ответ 3
toArray()
может быть решением.
Основываясь на документах, он сначала выполняет итерацию по всем курсорам на Mongo и только возвращает результаты один раз в виде массива.
http://docs.mongodb.org/manual/reference/method/cursor.toArray/
Это не похоже на list(coll.find())
или [doc for doc in coll.find()]
, которые извлекают один документ на Python за один раз и возвращаются к Mongo и выбирают следующий курсор.
Однако этот метод не был реализован на pyMongo... странный
Ответ 4
Как упоминалось выше @jmelesky, я всегда придерживаюсь такого же метода. Вот мой пример кода. Для хранения моего курсора twts_result, объявляющего список ниже для копирования. Используйте RAM, если вы можете хранить данные. Это решит проблему тайм-аут курсора, если никакая обработка и обновление не потребуются над вашей коллекцией, откуда вы выбрали данные.
Здесь я получаю твиты из коллекции.
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