Проблема в использовании list
при создании DataFrame
. Курсор используется все сразу, составляя список со словарями по 900 тыс., Что занимает много памяти.
Этого можно избежать, если создать пустой DataFrame
, а затем вытащить документы в пакетном режиме, несколько документов за раз, добавление их к DataFrame
.
def batched(cursor, batch_size):
batch = []
for doc in cursor:
batch.append(doc)
if batch and not len(batch) % batch_size:
yield batch
batch = []
if batch: # last documents
yield batch
df = pd.DataFrame()
for batch in batched(cursor, 10000):
df = df.append(batch, ignore_index=True)
10000 кажется приемлемым размером пакета, но вы можете изменить его в соответствии с вашими ограничениями памяти: чем выше, чем быстрее это закончится, но тем больше памяти он будет использовать во время работы.
ОБНОВЛЕНИЕ : добавьте некоторый тест
Обратите внимание, что при таком подходе запрос не требуется длятся дольше, а скорее наоборот, так как на самом деле требуется время, чтобы вытащить документы из mongodb в качестве словарей и разместить их в списке.
Вот некоторые тесты с документами 300K, которые показывают, как этот подход с правым batch_size
на самом деле даже быстрее, чем перетаскивать весь курсор в список:
%%time
df = pd.DataFrame(list(db.test.find().limit(300000)))
Процессорное время: пользователь 35,3 с, sys: 2,14 с, всего: 37,5 с Время настенного режима: 37,7 с
batch_size=10000
<- <strong>FASTEST
%%time
df = pd.DataFrame()
for batch in batched(db.test.find().limit(300000), 10000):
df = df.append(batch, ignore_index=True)
Процессорное время: пользователь 29,5 с, sys: 1,23 с, всего: 30,7 с Время настенного режима: 30,8 с
%%time
df = pd.DataFrame()
for batch in batched(db.test.find().limit(300000), 1000):
df = df.append(batch, ignore_index=True)
Время CPU: пользовательский 44,8 с, sys: 2,09 с, всего: 46,9 с Время наработки на стенку: 46,9 с
%%time
df = pd.DataFrame()
for batch in batched(db.test.find().limit(300000), 100000):
df = df.append(batch, ignore_index=True)
Время CPU: пользователь 34,6 с, sys: 1,15 с, всего: 35,8 с Время настенного режима: 36 с