Для Google App Engine (java), как установить и использовать размер блока в FetchOptions?

Я выполняю запрос, и в настоящее время он возвращает 1400 результатов, и из-за этого я получаю следующее предупреждение в файле журнала:

com.google.appengine.api.datastore.QueryResultsSourceImpl logChunkSizeWarning: этот запрос не имеет размера блока, установленного в FetchOptions, и вернул более 1000 результатов. Если наборы результатов такого размера являются общими для этого запроса, рассмотрите возможность установки размера блока для повышения производительности.

Я нигде не могу найти примеров того, как это реализовать, здесь есть вопрос о python, но поскольку я использую java и не понимаю python, я изо всех сил пытаюсь его перевести.

Кроме того, для выполнения этого запроса (ниже) требуется 17226cpu_ms, что кажется слишком длинным, я даже не могу представить, что произошло бы, если бы у меня было 5000 контактов и мне нужно было искать их на стороне клиента (как вы делаете с контактами googlemail! )

Код, который у меня есть:

    int index=0;
    int numcontacts=0;
    String[][] DetailList;

    PersistenceManager pm = PMF.get().getPersistenceManager();


    try {
        Query query = pm.newQuery(Contact.class, "AdminID == AID");
        query.declareParameters("Long AID");
        query.setOrdering("Name asc");
        List<Contact> Contacts = (List<Contact>) query.execute(AdminID);
        numcontacts=Contacts.size();
        DetailList=new String[numcontacts][5];

        for (Contact contact : Contacts) 
        {
            DetailList[index][0]=contact.getID().toString();
            DetailList[index][1]=Encode.EncodeString(contact.getName());
            index++;
        }
    } finally {
        pm.close();
    }
    return (DetailList);

Я нашел здесь следующие две записи:

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

  • Могу ли я вызвать запрос внутри цикла?
  • Как узнать, сколько раз повторять цикл?
  • Должен ли я просто проверять первый блок, который возвращается с количеством записей меньше, чем размер блока?

Как я могу обнаруживать подобные вещи без реального примера для подражания? Мне кажется, что другие люди здесь, кажется, «просто знают», как это делать ...!

Извините, если я задаю вопросы неправильно или я просто новичок в этом вопросе, но я не знаю, куда еще обратиться, чтобы разобраться в этом!


person johnvdenley    schedule 26.08.2011    source источник


Ответы (3)


Встреча с той же проблемой, и последний комментарий был месяц назад, так что вот что я узнал о тяжелых запросах набора данных.

Думаю, я собираюсь использовать технику "курсора запроса" после прочтения этих строк в статье (тот, что в python, кстати, упомянутый):

Эта статья написана для SDK версии 1.1.7. Начиная с версии 1.3.1, курсоры запросов (Java | Python) заменили методы, описанные ниже, и теперь являются рекомендуемым методом. для перелистывания больших наборов данных.

В документации Google о "курсоре запроса". В первой строке документа четко указано, зачем нужен курсор:

Курсоры запросов позволяют приложению выполнять запрос и получать пакет результатов, а затем получать дополнительные результаты для того же запроса в следующем веб-запросе без накладных расходов на смещение запроса.

В документации также есть пример Java сервлета, использующего технику курсора. Есть подсказка, как сгенерировать безопасный курсор для клиента. Наконец, показаны ограничения курсора.

Надеюсь, это поможет вам решить вашу проблему.

Небольшое напоминание о диапазоне и смещении, которое, если забыть, может сильно повлиять на производительность (и я сделал ^^):

Начальное смещение влияет на производительность: хранилище данных должно получить, а затем отбросить все результаты до начального смещения. Например, запрос с диапазоном 5,10 выбирает десять результатов из хранилища данных, затем отбрасывает первые пять и возвращает оставшиеся пять в приложение.


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

Query query = pm.newQuery(...);
// I would use of value below 1000 (gae limit) 
query.getFetchPlan().setFetchSize(numberOfRecordByFetch); 
person elkaonline    schedule 18.08.2012

Вот как я применяю FetchOptions, по сравнению с вашим примером кода, вам, возможно, придется немного подправить:

// ..... build the Query object
FetchOptions fetch_options =
    FetchOptions.Builder.withPrefetchSize(100).chunkSize(100);
QueryResultList<Entity> returned_entities =
    datastore_service_instance.prepare(query).asQueryResultList(fetch_options);

Конечно, цифры могут быть изменены (100).

Если мой ответ не то, что вы ищете, можете перефразировать свой вопрос (отредактировать).

Кстати, первый связанный вопрос написал я.

person Poni    schedule 28.08.2011
comment
Я не знаю, как перефразировать свой вопрос, поэтому просто отвечу на ваш комментарий. Я хотел просто заменить одну строчку кода: Список ‹Contact› Контакты = (Список ‹Contact›) query.execute (AdminID); с вашими двумя строчками кода? Если да, то можете ли вы мне помочь, изменив свой код, чтобы он соответствовал моим переменным? поскольку я не могу это понять. Я пробовал около 20 комбинаций своих переменных, но ничего не имеет смысла, поэтому я и задавал вышеупомянутые вопросы ... Одна вещь, которую я ударил пару раз, похоже, связана с тем фактом, что мой запрос выше импортируется как javax.jdo.Query; - person johnvdenley; 29.11.2011
comment
Может ли кто-нибудь помочь мне с этим, поскольку теперь это вызывает у меня проблему, которую я больше не могу решить! - person johnvdenley; 08.07.2012

Если вы используете хранилище данных напрямую, без JDO, тогда вы должны сделать что-то вроде следующего, чтобы установить размер блока при повторении данных:

Query query = new Query("entityname");
PreparedQuery preparedQuery = dataStore.prepare(query);
// the 200 should be less than 1000
FetchOptions options = FetchOptions.Builder.withChunkSize(200);
for (Entity result : preparedQuery.asIterable(options)) {
    ...
}
person Gray    schedule 06.09.2012
comment
Ненавижу это говорить, но я так и не понял, как это сделать. Мне только что позвонил клиент, чтобы сказать, что эта проблема снова подняла свою уродливую голову ... Они собирают 2044 записи данных из движка приложений, а я ' m снова появляется ошибка, чтобы установить размер блока, чтобы избежать проблемы ... По сути, я получаю тайм-аут при загрузке данных и все еще не понимаю, как решить проблему, для меня это ... бит в вашем цикле for выше, с которым я не знаю, как справиться. Будет ли хранилище данных возвращать результаты в виде 200 блоков, нужно ли мне затем рекомбинировать их перед отправкой клиенту? - person johnvdenley; 16.06.2015
comment
Да, я бы их рекомбинировал @johnvdenley. Вы разбиваете запрос, чтобы он завершился быстрее, а затем объединяете результаты, чтобы они равнялись всему списку. - person Gray; 16.06.2015