2013-02-03 25 views
4

对于谷歌数据存储中的100k +实体,ndb.query()。count()将在截止日期前取消,即使使用索引。我试着用produce_cursors选项,但只有iter()或fetch_page()会返回光标,但count()不会。ndb.query.count()在大型实体上的60秒查询截止日期失败

如何计算大型实体?

+0

我有同样的问题,任务队列中。问题不在于60秒'DeadlineExceededError'对于前端的要求,这对查询本身的60秒(ISH?)的最后期限,'_ToDatastoreError(ERR)... 超时:数据存储操作超时,或者数据暂时不可用。“呃,我猜这是OP的问题。 –

回答

2

要做一些昂贵的事情,你应该看看Task Queue Python API。基于任务队列API,Google App Engine提供了deferred library,我们可以使用它来简化运行后台任务的整个过程。

这里是你如何使用延迟库在你的应用的例子:

import logging 

def count_large_query(query): 
    total = query.count() 
    logging.info('Total entities: %d' % total) 

然后你可以从调用上述功能的应用程序中,如:

from google.appengine.ext import deferred 

# Somewhere in your request: 
deferred.defer(count_large_query, ndb.query()) 

虽然我仍然不确定count()是否会返回任何带有如此大数据存储的结果,但您可以使用此count_large_query()函数,而不是使用游标(untes TED):

LIMIT = 1024 
def count_large_query(query): 
    cursor = None 
    more = True 
    total = 0 
    while more: 
    ndbs, cursor, more = query.fetch_page(LIMIT, start_cursor=cursor, keys_only=True) 
    total += len(ndbs) 

    logging.info('Total entitites: %d' % total) 

要在本地尝试上述集LIMIT 4,检查是否在您的控制台可以看到Total entitites: ##线。


正如吉在评论中提及这不会扩大规模或者:

这仍然不能扩展(尽管它可能推迟的问题)。任务 有10分钟而不是1分钟,所以也许你可以将10x计为 许多实体。但它非常昂贵!如果你想正确解决这个问题,可以搜索分片 计数器(不幸的是,这是很多工作的 )。

所以你可能想看看best practices for writing scalable applications,尤其是sharding counters

+1

嗯。这仍然没有规模(尽管它可能推迟了这个问题)。任务有10分钟而不是1分钟,所以也许你可以计算10倍的实体。但它非常昂贵!如果你想正确地解决这个问题,可以搜索分片计数器(不幸的是它有很多工作)。 –

+0

@RayYan我我的答案更新圭多的评论后..所以考虑到这一点为好。 – Lipis

1

最好是使用谷歌应用程序引擎后端。 后端对用户请求的60秒截止期限和任务的10分钟截止期限免除,并且无限期地运行。 请看这里的文件:https://developers.google.com/appengine/docs/java/backends/overview

+0

谢谢,但即使是后端,查询截止日期60s是不可避免的。 –

+1

这是真的,这是数据库的API,超时而不是你是从调用它的平台。这是不可避免的,因为我从类似的问题/答案中找到了答案。 –

2

这确实是一个令人沮丧的问题。最近我在这方面做了一些工作,以获得一些统计数据 - 基本上是满足某些查询的实体的数量。 count()是一个好主意,但它受到数据存储RPC超时的困扰。

如果count()以某种方式支持游标,以便您可以在结果集中进行游标移动并简单地将所得到的整数相加而不是返回大量关键字仅将它们丢弃,那将会很不错。使用游标,您可以在所有1分钟/ 10分钟的界限内继续使用“传递接力棒”延迟方法。与count()(而不是fetch(keys_only=True)),你可以大大减少浪费,并希望提高RPC调用的速度,例如,,它需要时间一个令人震惊的量使用fetch(keys_only=True)办法数到100 - 在后台一个昂贵的主张。

分片计数器是一个很大的开销,如果你只需要/想定期计数统计数据(例如,我的系统中的所有账户的,例如,国家每日计数)。

+0

这里的解决方案是使用'db.Query.count',而不是*支持游标。这是几分钟计数和几秒钟之间的差异,当计数达数百万时。使用'deferred.defer'来存储和转发结果,在两个60秒的请求中可以计算出2M。请注意,即使使用'ndb'映射,也可以使用'db.Query.count'。 – technomage