将NDB数据存储区记录导出到云存储CSV文件

时间:2014-03-19 15:47:15

标签: google-app-engine csv mapreduce google-cloud-storage app-engine-ndb

在我的NDB数据存储区中,我有超过200万条记录。我想将按created_at日期分组的这些记录导出到Google云端存储上的CSV文件中。我计算出每个文件大约是1GB。

2014-03-18.csv, ~17000 records, ~1GB
2014-03-17.csv, ~17000 records, ~1GB
2014-03-18.csv, ~17000 records, ~1GB
...

我的第一种方法(伪代码):

import cloudstorage as gcs
gcs_file = gcs.open(date + '.csv', 'w')
query = Item.query().filter(Item.created_at >= date).filter(Item.created_at < date+1day)
records = query.fetch_page(50, cursor)
for record in records:
   gcs_file.write(record)

但是这(显然是?)引发了记忆问题:

Error: Exceeded soft private memory limit with 622.16 MB after servicing 2 requests total

我应该使用MapReduce管道,还是有办法让方法1工作?如果使用MapReduce:我可以过滤created_at而不迭代NDB中的所有记录吗?

3 个答案:

答案 0 :(得分:4)

考虑到记录的数量,您确实会发现内存错误。 当请求结束时,默认情况下会调用垃圾收集器,这就解释了为什么使用的内存会像这样增加。

在这种情况下,我通常会在获取每个页面后使用gc.collect()手动调用垃圾收集器。

它看起来像这样:

import cloudstorage as gcs
import gc

cursor = None
more = True
gcs_file = gcs.open(date + '.csv', 'w')
query = Item.query().filter(Item.created_at >= date).filter(Item.created_at < date+1day)

while more:
  records, cursor, more = query.fetch_page(50, cursor)
  gc.collect()
  for record in records:
    gcs_file.write(record)

gcs_file.close()

在很多情况下,它一直在为我工作。

答案 1 :(得分:1)

我终于明白了。由于所有数据都在NDB数据存储区中,因此我无法在本地测试所有数据,因此我发现logging.info("Memory Usage: %s", runtime.memory_usage().current())非常有用。 (使用from google.appengine.api import runtime导入)。

问题是&#34; In-Context Cache&#34; 查询结果被写回到上下文缓存中。 More information. 请参阅example to disable the In-Context Cache了解实体种类。

虽然我的计算有点错误。生成的CVS文件大约300 MB。它会在5分钟内生成/保存到Google云端存储中。

Memory consumption without gc.collect()

峰值内存消耗约为480MB。

相比之下,如上面评论中@brian所建议的gc.collect()循环(link)中添加了while True:,内存消耗峰值约为260MB。但是花了很长时间,大约20分钟。

enter image description here

答案 2 :(得分:0)

上下文缓存可能是您的问题的一部分,但fetch_page通常是一个漏洞的方法。如果您正在重复查询,请将您的工作包装在@ndb.toplevel中,以便在查询之间清除队列,垃圾收集可以更有效。