如何在Google AppEngine中汇总数据

时间:2011-03-27 09:02:09

标签: python google-app-engine google-cloud-datastore mapreduce

我正在尝试使用AppEngine实现对大型(ish)数据集的摘要视图。

我的模型看起来像:

def TxRecord(db.Model):
    expense_type = db.StringProperty()
    amount = db.IntegerProperty()

def ExpenseType(db.Model):
    name = db.StringProperty()
    total = db.IntegerProperty()

我的数据存储区包含100个TxRecord个实例,我想通过expense_type对它们进行总结。

在sql中它会是这样的:

select expense_type as name, sum(amount) as total 
    from TxRecord
    group by expense_type

我目前正在使用Python MapReduce framework使用以下映射器迭代所有TxRecords

def generate_expense_type(rec):
    expense_type = type.get_or_insert(name, name = rec.expense_type)
    expense_type.total += rec.amount

    yield op.db.Put(expense_type)

这似乎有效,但我觉得我必须使用shard_count为1来运行它,以确保总数不会超过并发写入。

我是否可以使用AppEngine来解决此问题的策略,还是它?

3 个答案:

答案 0 :(得分:3)

使用MapReduce框架是个好主意。如果使用MapReduce框架提供的计数器,则可以使用多个分片。因此,不是每次都修改数据存储区,而是可以执行以下操作:

yield op.counters.Increment("total_<expense_type_name>", rec.amount)

MapReduce完成后(希望比仅使用一个分片时快得多),然后您可以将最终的计数器复制到数据存储区实体中。

答案 1 :(得分:3)

MapReduce非常适合离线处理数据,我喜欢David处理计数器的解决方案(+1 upvote)。

我只是想提一下另一种选择:处理数据。请查看Brett Slatkin在IO 2010上发表的High Throughput Data Pipelines on App Engine演讲。

我在一个简单的框架(slagg)中实现了这项技术,您可能会找到我的grouping with date rollup useful示例。

答案 2 :(得分:3)

使用mapreduce是正确的方法。正如大卫建议的那样,计数器是一种选择,但它们不可靠(它们使用内存缓存),并且它们不是为大量计数器并行设计的。

您当前的mapreduce有几个问题:首先,get_or_insert每次调用时都会执行数据存储区事务。其次,然后更新事务外部的数量并再次异步存储它,生成您关注的并发问题。

至少在完全支持reduce之前,最好的选择是在事务中执行mapper中的整个更新,如下所示:

def generate_expense_type(rec):
    def _tx():
      expense_type = type.get(name)
      if not expense_type:
        expense_type = type(key_name=name)
      expense_type.total += rec.amount
      expense_type.put()
    db.run_in_transaction(expense_type)