カウントを行う1つの方法は次のようなものだと思います:
foo = db.GqlQuery("SELECT * FROM bar WHERE baz = 'baz')
my_count = foo.count()
私が気に入らないのは、カウントが最大 1000 に制限され、クエリがおそらく遅くなることです。回避策がある人はいますか?1つ考えていますが、きれいに感じません。GQL だけに本当の COUNT 関数があれば...
カウントを行う1つの方法は次のようなものだと思います:
foo = db.GqlQuery("SELECT * FROM bar WHERE baz = 'baz')
my_count = foo.count()
私が気に入らないのは、カウントが最大 1000 に制限され、クエリがおそらく遅くなることです。回避策がある人はいますか?1つ考えていますが、きれいに感じません。GQL だけに本当の COUNT 関数があれば...
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 Jehiah の応答に。
GAE でオブジェクト カウンターを取得するための公式で祝福された方法は、シャード カウンターを構築することです。非常に響きの良い名前にもかかわらず、これは非常に簡単です。
すべてのデータベースのカウント関数は遅い (例: O(n)) - GAE データストアはそれをより明白にします。Jehiah が示唆するように、計算されたカウントをエンティティに格納し、スケーラビリティが必要な場合はそれを参照する必要があります。
これは App Engine に限ったことではありません。他のデータベースでは、リクエストごとに数万件のレコードをカウントしようとすると、ページのレンダリング時間が指数関数的に増加し始めるまで、それをより適切に隠すことができます...
GqlQuery.count()
documentationによると、limit
を 1000 より大きい数値に設定できます。
from models import Troll
troll_count = Troll.all(keys_only=True).count(limit=31337)
人々が言ったように、シャードカウンターはこのような数を追跡する正しい方法ですが、ゲームの後半に(私のように)これを理解した場合は、オブジェクトの実際の数からカウンターを初期化する必要があります. しかし、これは Datastore Small Operations の無料クォータ (50,000 だと思います) を使い果たすのに最適な方法です。コードを実行するたびに、モデル オブジェクトと同じ数の op が使用されます。
私はそれを試していませんが、これは完全なリソースの浪費ですが.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
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
最善の回避策は少し直感に反するように思えるかもしれませんが、私のすべての 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() はインデックスの先頭から 1 つのレコードを返します。とても速いです。
次に、1000 番目のオブジェクト制限を超えて取得する場合は、次のようにします。
MyObj.all().filter('num > ' , 2345).fetch(67)
Aral Balkan の痛烈なレビュー: http://aralbalkan.com/1504を読んだとき、私はすでにこれを行っていました。イライラしますが、慣れて、これがリレーショナル DB の count() よりもはるかに高速であることに気付くと、気にならなくなります...