我正在撰写应用引擎卡拉OK目录应用。该应用程序非常简单:在第一个版本中,它提供了将CSV歌曲列表导入目录并显示它们的功能。
我遇到CSV导入问题:在我的开发环境中导入17,500条记录需要很长时间(14小时)。在生产环境中,它导入大约1000条记录,然后用代码500崩溃。我正在查看日志,但没有找到任何有用的线索。
class Song(ndb.Model):
sid = ndb.IntegerProperty()
title = ndb.StringProperty()
singer = ndb.StringProperty()
preview = ndb.StringProperty()
@classmethod
def new_from_csv_row(cls, row, parent_key):
song = Song(
sid=int(row['sid']),
title=row['title'],
singer=row['singer'],
preview=row['preview'],
key=ndb.Key(Song, row['sid'], parent=parent_key))
return song
class CsvUpload(webapp2.RequestHandler):
def get(self):
# code omit for brevity
def post(self):
catalog = get_catalog(…) # retrieve old catalog or create new
# upfile is the contents of the uploaded file, not the filename
# because the form uses enctype="multipart/form-data"
upfile = self.request.get('upfile')
# Create the songs
csv_reader = csv.DictReader(StringIO(upfile))
for row in csv_reader:
song = Song.new_from_csv_row(row, catalog.key)
song.put()
self.redirect('/upload')
sid,title,singer,preview
19459,Zoom,Commodores,
19460,Zoot Suit Riot,Cherry Poppin Daddy,
19247,You Are Not Alone,Michael Jackson,Another day has gone. I'm still all alone
如何加快导入操作?任何建议,提示或提示将不胜感激。
我遵循了Murph的建议并使用KeyProperty
将歌曲链接回目录。对于17,500条记录,结果大约需要4分20秒 - 这是一项巨大的进步。这意味着,我还没有完全理解NDB如何在App Engine中运行,我还有很长的路要走。
虽然有了很大改进,但4分钟以上仍然太长了。我现在正在研究Tim和Dave的建议,进一步缩短我的应用程序的响应时间。
答案 0 :(得分:1)
在Google App Engine的数据存储区中,对实体组的写入限制为每秒1次写入。
由于您为每首歌曲指定了“父”键,因此它们都会在一个实体组中结束,这非常慢。
使用KeyProperty来跟踪这种关系是否可以接受?虽然数据可能会有更多的一致性问题,但速度会快得多。
答案 1 :(得分:1)
除了另一个答案:实体组,如果导入过程需要超过60秒,使用任务,那么你有10分钟的运行时间。
将csv存储为实体中的BlobProperty(如果压缩< 1MB)或GCS更大,然后启动从存储中检索CSV然后进行处理的任务。
答案 2 :(得分:1)
首先,蒂姆走在正确的轨道上。如果您无法在60秒内完成工作,请遵循任务。但如果你不能在10分钟内完成工作,请回到App Engine MapReduce,这将分配处理你的csv跨多个任务的工作。请参考demo program,其中包含您需要的部分内容。
对于开发时间缓慢,启动dev_appserver时是否使用--use_sqlite
选项?
Murph触及你问题的另一部分。使用实体组,您可以对可以执行的插入数(每个实体组)进行速率限制。尝试使用单个父级插入17,500行并不能很好地工作。这将需要大约5个小时。
那么,你真的需要一致的阅读吗?如果这是一次性上传,你可以进行非祖先插入(将目录作为属性),然后稍等一下,使数据最终变得一致吗?这简化了查询。
如果你真的,绝对需要一致的读取,你可能需要在多个父键之间拆分你的写入。这会增加您的写入速度,但会使您的祖先查询更加复杂。