Frage

ich meine, ein Weg, um eine Zählung zu tun ist, wie folgt aus:

foo = db.GqlQuery("SELECT * FROM bar WHERE baz = 'baz')
my_count = foo.count()

Was ich nicht mag, ist, meine Zählung bis 1000 max begrenzt wird und meine Abfrage wird wahrscheinlich langsam sein. Jemand da draußen mit einer Vermeidung des Problems? Ich habe man sich vor Augen, aber nicht sauber fühlen. Wenn nur GQL hatte eine echte COUNT Funktion ...

War es hilfreich?

Lösung

1 bis Jehija Antwort.

Offizielle und gesegnete Methode auf immer Indikatoren auf GAE ist sharded Zähler . Trotz stark klingenden Namen, das ist ziemlich einfach.

Andere Tipps

Sie haben Ihr Denken kippen, wenn sie mit einem skalierbaren Datenspeicher wie GAE arbeiten Sie Ihre Berechnungen nach vorne zu tun. In diesem Fall, dass Sie brauchen, um Zähler für jede baz bedeutet und sie zu erhöhen, wenn Sie einen neuen bar hinzufügen, statt zum Zeitpunkt der Anzeige zu zählen.

class CategoryCounter(db.Model):
    category = db.StringProperty()
    count = db.IntegerProperty(default=0)

dann, wenn ein Bar-Objekt erstellen, erhöht den Zähler

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')

Jetzt haben Sie eine einfache Möglichkeit, die Zählung für eine bestimmte Kategorie abrufen

CategoryCounter.filter('category =',category_name).get().count

Count-Funktionen in allen Datenbanken sind langsam (zB O (n)) - der GAE-Datenspeicher macht nur, dass offensichtlicher. Wie Jehija vermuten lässt, müssen Sie die berechnete Zählung in einer Einheit speichern und das verweisen, wenn Sie Skalierbarkeit möchten.

Dies ist auf App Engine nicht eindeutig zuzuordnen - andere Datenbanken verstecken es nur besser, bis zu dem Punkt, wo Sie Zehntausende von Datensätzen mit jeder Anforderung zu zählen sind, und lassen Sie Ihre Seite machen beginnt exponentiell zu erhöhen .. .

Nach der GqlQuery.count() Dokumentation , können Sie die Set limit werden einige Zahl größer als 1000:

from models import Troll
troll_count = Troll.all(keys_only=True).count(limit=31337)

sharded Zähler sind der richtige Weg, den Überblick über Zahlen, so zu halten, wie die Leute gesagt haben, aber wenn man diese Zahl spät im Spiel aus (wie ich), dann werden Sie die Zähler von einer tatsächlichen Zahl initialisieren müssen Objekte. Aber das ist eine gute Möglichkeit, durch Ihr freies Kontingent von Datastor Kleine Operationen zu verbrennen (50.000 glaube ich). Jedes Mal, wenn Sie den Code ausführen, wird es so viele ops aufbrauchen, da es Modellobjekte sind.

Ich habe es nicht ausprobiert, und dies ist ein völlige Ressource Schwein, aber vielleicht mit .fetch() Iterieren und Angabe des Offset funktionieren würde?

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-Lösung arbeitet mit einer wenig Gefummel:

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

Wir haben jetzt Datastor Statistik, die verwendet werden kann Unternehmen zählen und andere Daten abzufragen. Diese Werte nicht immer spiegeln die jüngsten Veränderungen, wie sie aktualisiert werden einmal alle 24-48 Stunden. Schauen Sie sich die Dokumentation (siehe Link unten) für weitere Informationen:

Datastor Statistik

Wie @Dimu wies darauf hin, die von Google berechneten Statistiken auf einer periodischen Basis sind ein anständiger Go-to-Ressource, wenn genaue Zählungen nicht benötigt werden, und die% der Datensätze nicht drastisch während einem bestimmten Tag zu ändern.

Um die Statistiken für eine bestimmte Art abzufragen, können Sie die folgende GQL Struktur verwenden:

select * from __Stat_Kind__ where kind_name = 'Person'

Es gibt eine Reihe von Eigenschaften, die durch diese zurückgegeben, die hilfreich sind:

  • count - die Anzahl der Einheiten dieser Art
  • bytes - Gesamtgröße aller gespeicherten Entitäten dieser Art
  • timestamp - ein von Datum / Zeit, wenn die Statistiken wurden zuletzt berechneten

Beispiel-Code

eine Folgefrage als Kommentar auf meine Antwort geschrieben zu beantworten, ich sende nun einige Beispiel C# Code, den ich verwende, die zwar nicht so robust sein kann, wie es sein sollte, scheint aber für mich OK zu arbeiten :

/// <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);
}

Die beste Abhilfe könnte ein wenig kontraintuitiv erscheinen, aber es funktioniert gut in allen meinen appengine apps. Anstatt sich auf die ganze Zahl KEY verlassen und count () Methoden, fügen Sie ein Integer-Feld des eigenen in den Datentyp. Es könnte eine Verschwendung scheinen, bis Sie tatsächlich mehr als 1000 Datensätze haben, und Sie plötzlich entdecken, dass holen () und limit () NICHT PAST 1000 RECORD GRENZ ARBEITEN.

def MyObj(db.Model):
  num = db.IntegerProperty()

Wenn Sie ein neues Objekt erstellen, müssen Sie manuell die höchste Taste abgerufen werden:

max = MyObj.all().order('-num').get()
if max : max = max.num+1
else : max = 0
newObj = MyObj(num = max)
newObj.put()

Das mag wie eine Verschwendung von einer Abfrage erscheinen, aber get () gibt einen einzelnen Datensatz aus der Spitze des Index. Es ist sehr schnell.

Wenn Sie dann vorbei an der 1000. Objekt Grenze holen möchten, können Sie einfach tun:

MyObj.all().filter('num > ' , 2345).fetch(67)

Ich hatte dies bereits getan, wenn ich Aral Balkan die vernichtende Kritik lesen: http://aralbalkan.com/1504. Es ist frustrierend, aber wenn man sich daran gewöhnen, und Sie erkennen, wie viel schneller ist dies als count () auf einer relationalen db, Sie haben nichts dagegen ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top