2011-06-15 59 views
1

我在尝试将36k法语城市插入BigTable时遇到了一些问题。我解析一个CSV文件,并把每一行到数据存储使用这段代码:将成千上万的实体插入BigTable

import csv 
from databaseModel import * 
from google.appengine.ext.db import GqlQuery 

def add_cities(): 
spamReader = csv.reader(open('datas/cities_utf8.txt', 'rb'), delimiter='\t', quotechar='|') 
mylist = [] 
for i in spamReader: 
    region = GqlQuery("SELECT __key__ FROM Region WHERE code=:1", i[2].decode("utf-8")) 
    mylist.append(InseeCity(region=region.get(), name=i[11].decode("utf-8"), name_f=strip_accents(i[11].decode("utf-8")).lower())) 
db.put(mylist) 

它以大约5分钟(!!!)与本地开发服务器做到这一点,甚至10时删除他们用db.delete()函数。 当我尝试在线调用包含add_cities()的test.py页面时,达到30秒超时。 我来自MySQL世界,我认为这是一个真正的耻辱,不要在不到一秒钟内添加36k个实体。我可能会在做错的方式做到这一点,所以我指的是你:

  • 为什么这么慢?
  • 有没有什么办法在合理的时间内做到这一点?

谢谢:)

+0

为什么不尝试使用[批量上传](http://code.google.com/intl/it/appengine/docs/python/tools/uploadingdata.html)? – systempuntoout 2011-06-15 20:32:44

+0

因为我需要用在线解析的数据做同样的事情,它不会在数据文件中... – 2011-06-15 20:36:58

回答

2

首先,它是数据存储,不是Bigtable。数据存储使用bigtable,但是它增加了更多。

这是如此缓慢的主要原因是您正在为您添加的每条记录进行查询(在'地区'类)。这不可避免地会大幅放缓。有两件事情可以做,以加快速度:

  • 使用Regioncodekey_name,让你做一个更快的数据存储获得的,而不是一个查询。实际上,由于您只需要区域的引用属性的关键字,所以在这种情况下根本不需要获取区域。
  • 缓存内存中的区域列表,或跳过将其存储在数据存储中。就其性质而言,我猜测区域既是一个小列表,也不经常变化,因此可能不需要将它存储在数据存储区中。

此外,您应该在加载大量数据时使用mapreduce framework以避免超时。它也内置支持从blobstore blob读取CSV。

2

使用Task Queue。如果您希望快速处理数据集,请使用偏移值让您的上传处理程序为每个500的子集创建一个任务。

0

FWIW我们使用mapreduce将大型CSV处理到数据存储中,并在任务内部进行一些初始处理/验证。即使任务目前也有一个限制(10分钟),但对于您的数据大小来说可能还不错。

确定你是否在做插入等。尽可能批处理 - 不要插入单个记录,并且查找同样 - get_by_keyname允许您传入一组键。 (我相信db现在有200条记录的限制吗?)

Mapreduce对于你现在正在做的事情可能是过度的,但它绝对值得包装你的头,这是必须有更大的数据集。

最后,SDK上的任何时间都是毫无意义的 - 将其视为调试器而非其他任何事情!