我认为计算的一种方法是这样的:
foo = db.GqlQuery("SELECT * FROM bar WHERE baz = 'baz')
my_count = foo.count()
我不喜欢的是我的数量将限制为最多1000次,我的查询可能会很慢。那里的人有解决方法吗?我有一个想法,但它感觉不干净。如果只有GQL有一个真正的COUNT函数......
答案 0 :(得分:20)
在使用像GAE这样的可扩展数据存储区时,您必须提前考虑进行计算。在这种情况下,这意味着您需要为每个baz
保留计数器,并在添加新bar
时递增它们,而不是在显示时计数。
class CategoryCounter(db.Model):
category = db.StringProperty()
count = db.IntegerProperty(default=0)
然后在创建Bar对象时,递增计数器
def createNewBar(category_name):
bar = Bar(...,baz=category_name)
counter = CategoryCounter.filter('category =',category_name).get()
if not counter:
counter = CategoryCounter(category=category_name)
else:
counter.count += 1
bar.put()
counter.put()
db.run_in_transaction(createNewBar,'asdf')
现在您可以轻松获取任何特定类别的计数
CategoryCounter.filter('category =',category_name).get().count
答案 1 :(得分:17)
+1以耶希亚的回应。
在GAE上获取对象计数器的官方和祝福方法是构建sharded counter。尽管声名鹊起,但这非常简单。
答案 2 :(得分:7)
所有数据库中的计数函数都很慢(例如,O(n)) - GAE数据存储区使这一点变得更加明显。正如Jehiah建议的那样,您需要将计算出的计数存储在实体中,如果您想要可伸缩性,请参考该数据。
这不是App Engine独有的 - 其他数据库只是更好地隐藏它,直到你试图用每个请求计算成千上万条记录,并且你的页面渲染时间开始呈指数增长。
答案 3 :(得分:2)
根据GqlQuery.count()
documentation,您可以将limit
设置为大于1000的某个数字:
from models import Troll
troll_count = Troll.all(keys_only=True).count(limit=31337)
正如人们所说的那样,分片计数器是跟踪这样的数字的正确方法,但是如果你在游戏的后期(比如我)弄清楚了这一点,那么你需要从实际计数中初始化计数器对象。但这是一种很好的方式来烧掉你的数据存储小型操作的免费配额(我认为是50,000)。每次运行代码时,它都将使用与模型对象一样多的操作。
答案 4 :(得分:0)
我还没有尝试过,这是一个彻头彻尾的资源困境,但也许用.fetch()
进行迭代并指定偏移量会起作用?
LIMIT=1000
def count(query):
result = offset = 0
gql_query = db.GqlQuery(query)
while True:
count = gql_query.fetch(LIMIT, offset)
if count < LIMIT:
return result
result += count
offset += LIMIT
答案 5 :(得分:0)
orip的解决方案稍作调整:
LIMIT=1000
def count(query):
result = offset = 0
gql_query = db.GqlQuery(query)
while True:
count = len(gql_query.fetch(LIMIT, offset))
result += count
offset += LIMIT
if count < LIMIT:
return result
答案 6 :(得分:0)
我们现在拥有可用于查询实体计数和其他数据的数据存储统计信息。这些值并不总是反映最近的更改,因为它们每24-48小时更新一次。查看文档(参见下面的链接)了解更多详细信息:
答案 7 :(得分:0)
正如@Dimu指出的那样,谷歌定期计算的统计数据是一个不错的首选资源,当不需要精确计数时,记录的百分比在任何特定日期都不会发生剧烈变化。
要查询给定种类的统计信息,可以使用以下GQL结构:
select * from __Stat_Kind__ where kind_name = 'Person'
有很多属性可以帮助您返回:
count
- 此类实体的数量bytes
- 此类存储的所有实体的总大小timestamp
- 上次计算统计数据的日期/时间示例代码
要回答作为对我的回答发表评论的后续问题,我现在提供一些我正在使用的示例C#
代码,这些代码可能不会像应有的那样强大,但似乎工作对我来说还可以:
/// <summary>Returns an *estimated* number of entities of a given kind</summary>
public static long GetEstimatedEntityCount(this DatastoreDb database, string kind)
{
var query = new GqlQuery
{
QueryString = $"select * from __Stat_Kind__ where kind_name = '{kind}'",
AllowLiterals = true
};
var result = database.RunQuery(query);
return (long) (result?.Entities?[0]?["count"] ?? 0L);
}
答案 8 :(得分:-1)
最好的解决方法可能看起来有点违反直觉,但它在我的所有appengine应用程序中都很有用。您可以将自己的整数字段添加到数据类型,而不是依赖于整数KEY和count()方法。在您实际拥有超过1000条记录之前,它可能看起来很浪费,并且您突然发现fetch()和limit()不能使用1000记录边界。
def MyObj(db.Model):
num = db.IntegerProperty()
创建新对象时,必须手动检索最高键:
max = MyObj.all().order('-num').get()
if max : max = max.num+1
else : max = 0
newObj = MyObj(num = max)
newObj.put()
这似乎浪费了查询,但get()返回索引顶部的单个记录。它非常快。
然后,当您想要获取超过第1000个对象限制时,您只需执行以下操作:
MyObj.all().filter('num > ' , 2345).fetch(67)
当我读到Aral Balkan严厉的评论时,我已经这样做了:http://aralbalkan.com/1504。这很令人沮丧,但是当你习惯它并且你意识到它比关系数据库上的count()快多少时,你就不会介意......