如何在googleappengin中汇总数据

2024-06-26 11:22:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试使用AppEngine对一个大的(ish)数据集实现一个summary视图。在

我的模型看起来像:

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

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

我的数据存储包含TxRecord的100K个实例,我想用expense_type来总结这些实例。在

在sql中,它类似于:

^{pr2}$

我当前所做的是使用Python MapReduce framework来迭代所有的{},使用以下映射器:

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)

这似乎是可行的,但我觉得我必须使用1的shard_count来运行它,以确保总数不会被并发写入覆盖。在

有没有一个策略可以让我用AppEngine来解决这个问题呢?在


Tags: 数据实例namedbmodeldeftypeamount
3条回答

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

当前的mapreduce有两个问题:首先,get_or_insert每次调用它时都会执行一个数据存储事务。其次,更新事务外部的金额,并第二次异步存储它,从而产生您所关心的并发问题。在

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

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)

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

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

在MapReduce完成后(希望比只使用一个shard时快得多),然后可以将完成的计数器复制到数据存储实体中。在

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

我只想提一下另一个选择:在数据进来时对其进行处理。看看Brett Slatkin在IO 2010中的High Throughput Data Pipelines on App Engine演讲。在

我已经在一个简单的框架(slagg)中实现了该技术,您可能会发现我的grouping with date rollup useful示例。在

相关问题 更多 >