Подтвердить что ты не робот

Каков наилучший способ подсчета результатов в GQL?

Я считаю, что один способ сделать подсчет выглядит следующим образом:

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

Что мне не нравится, мой счет будет ограничен 1000 макс, и мой запрос, вероятно, будет медленным. Кто-нибудь там с обходным решением? Я имею в виду, но он не чувствует себя чистым. Если только GQL имел реальную функцию COUNT...

4b9b3361

Ответ 1

+1 к ответу Иехии.

Официальный и благословенный метод получения счетчиков объектов в GAE заключается в создании sharded counter. Несмотря на сильно звучащее имя, это довольно просто.

Ответ 2

Вы должны перевернуть свое мышление при работе с масштабируемым хранилищем данных, например 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

Ответ 3

Функции подсчета во всех базах данных медленны (например, O (n)) - хранилище данных GAE делает это более очевидным. Как предполагает Иехия, вам нужно сохранить вычисляемый счет в сущности и ссылаться на это, если вы хотите масштабируемость.

Это не уникально для App Engine - другие базы данных просто спрятали его лучше, вплоть до момента, когда вы пытаетесь подсчитать десятки тысяч записей с каждым запросом, а время рендеринга страницы начинает экспоненциально возрастать...

Ответ 4

В соответствии с GqlQuery.count() документацией вы можете установить limit как число больше 1000:

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

Зашаренные счетчики - это правильный способ отслеживать такие числа, как это было сказано людьми, но если вы выясните это в конце игры (например, я), вам нужно будет инициализировать счетчики с фактического количества объекты. Но это отличный способ прорваться через вашу свободную квоту на Small Small Operations (50 000, я думаю). Каждый раз, когда вы запускаете код, он будет использовать столько операционных систем, сколько есть объектов модели.

Ответ 5

Я не пробовал, и это полный ресурс hog, но, возможно, повторение с помощью .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

Ответ 6

Решение 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

Ответ 7

Теперь мы имеем статистику Datastore, которая может использоваться для запроса количества объектов и других данных. Эти значения не всегда отражают самые последние изменения, поскольку они обновляются каждые 24-48 часов. Ознакомьтесь с документацией (см. Ссылку ниже) для более подробной информации:

Статистика хранилища данных

Ответ 8

Лучшее обходное решение может показаться немного контр-интуитивным, но оно отлично работает во всех приложениях 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)

Я уже это сделал, когда прочитал обзор речей Арала Балкан: http://aralbalkan.com/1504. Это расстраивает, но когда вы привыкаете к этому, и вы понимаете, насколько это быстрее, чем count() на реляционном db, вы не будете возражать...