Вопрос

Как я могу извлечь более 1000 записей из хранилища данных и поместить все в один список для передачи в django?

Это было полезно?

Решение

Начиная с версии 1.3.6 (выпущенной 17 августа 2010 г.) вы МОЖЕТЕ

Из журнала изменений:

  

Результаты запросов count () хранилища данных () и смещений для всех запросов хранилища данных больше не ограничены 1000 .

Другие советы

Просто для справки - лимит выборки в 1000 записей теперь отменен:

http://googleappengine .blogspot.com/2010/02/app-engine-sdk-131-including-major.html

Цитата:

Не более 1000 ограничить результат - это право:с добавлением курсоров и кульминацией многих более мелких Улучшений стабильности и производительности хранилища данных за последние несколько месяцев, мы теперь достаточно уверены, чтобы полностью устранить ограничение на максимальный результат.Выполняете ли вы выборку, повторяете или используете курсор, количество результатов не ограничено.

App Engine дает вам хороший способ "подкачки страниц" через 1000 результатов, упорядочив ключи и используя последний ключ в качестве следующего смещения. Здесь даже приведен пример кода:

http://code.google.com/appengine /docs/python/datastore/queriesandindexes.html#Queries_on_Keys

Хотя их пример распределяет запросы по многим запросам, вы можете изменить размер страницы с 20 на 1000 и выполнять запросы в цикле, комбинируя наборы запросов. Кроме того, вы можете использовать itertools для связывания запросов без их оценки до того, как они понадобятся.

Например, чтобы посчитать, сколько строк превышает 1000:

class MyModel(db.Expando):
    @classmethod
    def count_all(cls):
        """
        Count *all* of the rows (without maxing out at 1000)
        """
        count = 0
        query = cls.all().order('__key__')

        while count % 1000 == 0:
            current_count = query.count()
            if current_count == 0:
                break

            count += current_count

            if current_count == 1000:
                last_key = query.fetch(1, 999)[0].key()
                query = query.filter('__key__ > ', last_key)

        return count

Каждый раз, когда это становится ограничением, я всегда задаюсь вопросом: почему вам нужно более 1000 результатов? " Знаете ли вы, что сами Google не дают более 1000 результатов? Попробуйте выполнить поиск = "noreferrer"> http://www.google.ca/search?hl=en&client=firefox-a&rls=org.mozilla:en-US:official&hs=qhu&q=1000+results&start = 1000 & sa = N Я не знал этого до недавнего времени, потому что я никогда не тратил время на переход на сотую страницу результатов поиска по запросу.

Если вы на самом деле возвращаете пользователю более 1000 результатов, я думаю, что есть более серьезная проблема, чем тот факт, что хранилище данных не позволит вам это сделать.

Одна из возможных (законных) причин, по которой нужно так много результатов, заключается в том, что вы выполняли большую операцию с данными и представляли сводку (например, каково среднее значение всех этих данных). Решение этой проблемы (о которой говорится в докладе о вводе-выводе Google) состоит в том, чтобы вычислять сводные данные на лету, как они поступают, и сохранять их.

Ты не можешь.

В части часто задаваемых вопросов говорится, что вы никак не можете получить доступ за пределы строки 1000 запроса, увеличение "СМЕЩЕНИЯ" просто приведет к сокращению результирующего набора,

т. е.:Возвращается СМЕЩЕНИЕ 999 --> 1 результат.

Из Википедии:

App Engine ограничивает максимальное количество строк возвращаемых от объекта get до 1000 строк на вызов хранилища данных.Большинство веб-приложений баз данных используют подкачку и кэширование и, следовательно, не требуют этого большого количества данных одновременно, так что это не проблема в большинстве сценариев.[требуется цитирование ] Если приложению требуется более 1000 записей на операцию, оно может использовать свое собственное клиентское программное обеспечение или страницу Ajax для выполнения операции с неограниченным количеством строк.

От http://code.google.com/appengine/docs/whatisgoogleappengine.html

Другим примером ограничения сервиса является количество результатов, возвращаемых запросом.Запрос может возвращать не более 1000 результатов.Запросы, которые бы возвращали больше результатов, возвращают только максимум.В этом случае запрос, который выполняет такой запрос, вряд ли вернет запрос до истечения времени ожидания, но ограничение действует для экономии ресурсов в хранилище данных.

От http://code.google.com/appengine/docs/datastore/gqlreference.html

Примечание:Максимальное значение предложения LIMIT составляет 1000.Если указано ограничение, превышающее максимальное, используется максимальное значение.Этот же максимум применим к методу fetch() класса GqlQuery.

Примечание:Подобно параметру offset для метода fetch(), СМЕЩЕНИЕ в строке запроса GQL не уменьшает количество объектов, извлекаемых из хранилища данных.Это влияет только на то, какие результаты возвращаются методом fetch() .Запрос со смещением имеет характеристики производительности, которые линейно соответствуют размеру смещения .

От http://code.google.com/appengine/docs/datastore/queryclass.html

Аргументы limit и offset определяют сколько результатов извлекается из хранилища данных и сколько возвращается методом fetch():

  • Хранилище данных извлекает результаты смещения + ограничения для приложения.Первыми результатами смещения являются нет пропускается самим хранилищем данных.

  • Метод fetch() пропускает первые результаты смещения, затем возвращает остальные (предельные результаты).

  • Характеристики производительности запроса соответствуют линейно величине смещения плюс предел.

Что это означает, так это

Если у вас единичный запрос, невозможно запросить что-либо за пределами диапазона 0-1000.

Увеличение смещения просто увеличит значение 0, так что

LIMIT 1000  OFFSET 0    

Вернет 1000 строк,

и

LIMIT 1000 OFFSET 1000 

Вернется 0 строк, таким образом, делая невозможным получение 2000 результатов вручную или с помощью API с помощью одного синтаксиса запроса.

Единственное правдоподобное исключение

Заключается в создании числового индекса в таблице, т.е.:

 SELECT * FROM Foo  WHERE ID > 0 AND ID < 1000 

 SELECT * FROM Foo WHERE ID >= 1000 AND ID < 2000

Если ваши данные или запрос не могут иметь этот жестко заданный идентификатор "ID", то вы не повезло

Эта проблема с лимитом в 1 КБ устранена.

query = MyModel.all()
for doc in query:
    print doc.title

Обрабатывая объект Query как итеративный: итератор получает результаты из хранилища данных небольшими партиями, что позволяет приложению прекратить итерацию по результатам, чтобы избежать выборки больше, чем необходимо. Итерация останавливается, когда все результаты, соответствующие запросу, были получены. Как и в fetch (), интерфейс итератора не кэширует результаты, поэтому создание нового итератора из объекта Query повторно выполнит запрос.

Максимальный размер партии - 1 КБ. И у вас все еще есть автоматические квоты хранилища данных.

Но в плане 1.3.1 SDK они ввели курсоры, которые можно сериализовать и сохранить, чтобы в будущем вызов мог начать запрос с того места, где он был остановлен в последний раз.

Предел записи 1000 - это жесткий предел в Google AppEngine.

Эта презентация http: / /sites.google.com/site/io/building-scalable-web-applications-with-google-app-engine объясняет, как эффективно перелистывать данные с помощью AppEngine.

(В основном, используя числовой идентификатор в качестве ключа и указав предложение WHERE для идентификатора.)

Извлечение, хотя удаленный API все еще имеет проблемы, когда более 1000 записей. Мы написали эту крошечную функцию для перебора таблицы по частям:

def _iterate_table(table, chunk_size = 200):
    offset = 0
    while True:
        results = table.all().order('__key__').fetch(chunk_size+1, offset = offset)
        if not results:
            break
        for result in results[:chunk_size]:
            yield result
        if len(results) < chunk_size+1:
            break
        offset += chunk_size

мы используем что-то в нашем классе ModelBase , а именно:

@classmethod
def get_all(cls):
  q = cls.all()
  holder = q.fetch(1000)
  result = holder
  while len(holder) == 1000:
    holder = q.with_cursor(q.cursor()).fetch(1000)
    result += holder
  return result

Это позволяет обойти ограничение в 1000 запросов для каждой модели, не задумываясь об этом. Я полагаю, что ключ версии будет так же легко реализовать.

class Count(object):
def getCount(self,cls):
    class Count(object):
def getCount(self,cls):
    """
    Count *all* of the rows (without maxing out at 1000)
    """
    count = 0
    query = cls.all().order('__key__')


    while 1:
        current_count = query.count()
        count += current_count
        if current_count == 0:
            break

        last_key = query.fetch(1, current_count-1)[0].key()
        query = query.filter('__key__ > ', last_key)

    return count
entities = []
for entity in Entity.all():
    entities.append(entity)

Просто так. Обратите внимание, что для каждого объекта существует RPC, который намного медленнее, чем выборка кусками. Поэтому, если вы беспокоитесь о производительности, сделайте следующее:

Если у вас менее 1 млн. предметов:

entities = Entity.all().fetch(999999)

В противном случае используйте курсор.

Следует также отметить, что:

Entity.all().fetch(Entity.all().count())

возвращает максимум 1000 и не должен использоваться.

JJG: ваше решение выше, отличное, за исключением того, что оно вызывает бесконечный цикл, если у вас 0 записей. (Я узнал об этом во время тестирования некоторых моих отчетов локально).

Я изменил начало цикла while, чтобы он выглядел так:

while count % 1000 == 0:
    current_count = query.count()
    if current_count == 0:
        break

Чтобы добавить содержимое двух запросов вместе:

list1 = first query
list2 = second query
list1 += list2

Список 1 теперь содержит все 2000 результатов.

Предлагаемое решение работает только в том случае, если записи сортируются по ключу ... Если вы сначала сортируете по другому столбцу, вам все равно нужно использовать предложение limit (offset, count), тогда ограничение 1000 записей по-прежнему применяется. То же самое, если вы используете два запроса: один для получения индексов (с условиями и сортировкой), а другой - с использованием где index in () с подмножеством индексов из первого результата, так как первый запрос не может вернуть более 1000 ключей? (В разделе Запросы по ключам Google четко не указано, нужно ли сортировать по ключу , чтобы снять ограничение в 1000 результатов)

Это близко к решению, предоставленному Габриэлем, но не извлекает результаты, оно просто их считает:

count = 0
q = YourEntityClass.all().filter('myval = ', 2)
countBatch = q.count()
while countBatch > 0:
    count += countBatch
    countBatch = q.with_cursor(q.cursor()).count()

logging.info('Count=%d' % count)

Отлично работает для моих запросов и работает быстро (1,1 секунды для подсчета 67 000 объектов)

Обратите внимание, что запрос не должен быть фильтром неравенства или набором, иначе курсор не будет работать, и вы получите это исключение:

  

AssertionError: курсор недоступен для MultiQuery (запросы с использованием операторов «IN» или «!»)

Если вы используете NDB:

@staticmethod
def _iterate_table(table, chunk_size=200):
    offset = 0
    while True:
        results = table.query().order(table.key).fetch(chunk_size + 1, offset=offset)
        if not results:
            break
        for result in results[:chunk_size]:
            yield result
        if len(results) < chunk_size + 1:
            break
        offset += chunk_size
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top