Хранилище данных App Engine не поддерживает оператор ИЛИ

Я пытаюсь запросить в хранилище данных Google что-то вроде (с pm -> persistanceManager):

String filters = "(  field == 'value' ||  field == 'anotherValue' )";
Query query = pm.newQuery(myType.class, filters);

Когда я выполняю - я возвращаюсь: хранилище данных App Engine не поддерживает оператор ИЛИ.

Как лучше всего подходить людям к таким запросам?

Любая помощь приветствуется!

8 ответов

Решение

Выполните несколько запросов. Хранилище данных, как и все другие базы данных, не может эффективно выполнять дизъюнкции. В отличие от других баз данных, это создает трудности для пользователя, чтобы понять, что то, что вы делаете, неэффективно. Ваше единственное решение - выполнить несколько запросов - по одному для каждого или - и объединить их.

Я не знаю, поддерживают ли реализации GAE JDO и JPA, но используя низкоуровневый API, вы можете использовать оператор IN для этого в одном запросе.

Query query = new Query("Issue");
List<String> list = Arrays.asList("NEW", "OPEN", "ACCEPTED");
query.addFilter("status", FilterOperator.IN, list);

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
PreparedQuery preparedQuery = datastore.prepare(query);
for (Entity entity : preparedQuery.asIterable()) {
    // should iterate over 'NEW', 'OPEN' and 'ACCEPTED' issues
}

Согласно Google App Engine - Запросы и индексы:

Фильтры запросов

Фильтр определяет имя поля, оператор и значение. Значение должно быть предоставлено приложением; он не может ссылаться на другое свойство или рассчитываться в терминах других свойств. Оператор может быть любым из следующих: < <= == >= >

Примечание. Интерфейс хранилища данных Java не поддерживает операторы фильтра!= И IN, которые реализованы в интерфейсе хранилища данных Python. (В интерфейсе Python эти операторы реализованы в клиентских библиотеках в виде нескольких запросов к хранилищу данных; они не являются функциями самого хранилища данных.)

Предметом фильтра может быть любое поле объекта, включая первичный ключ и родительский объект группы сущностей (см. Транзакции).

Сущность должна соответствовать всем фильтрам, чтобы быть результатом. В строковом синтаксисе JDOQL указано несколько фильтров, разделенных && (логическое "и"). Другие логические комбинации фильтров (логические "или", "не") не поддерживаются.

Из-за того, как хранилище данных App Engine выполняет запросы, один запрос не может использовать фильтры неравенства (< <= >= >) на более чем одно свойство. Допускается использование нескольких фильтров неравенства для одного и того же свойства (например, для запроса диапазона значений). См. Ограничения на запросы.

По сути, вам либо придется реструктурировать ваши данные, чтобы вы могли найти то, что вы ищете, с одним условием или несколькими условиями "и", либо вам придется получать данные с помощью двух (или более) запросов. и отфильтруйте / объедините это в своем коде.

Извините, что опоздал на игру... Я только что наткнулся на ваш вопрос сегодня.

Другой способ "симулировать" поведение "IN" и "OR" - использовать API "низкого уровня" Datastore API. DatastoreService поддерживает метод get (), который принимает коллекцию ключей и возвращает карту всех сущностей, которые соответствуют переданным в ключи. Это интерфейс, но есть удобный DatastoreServiceFactory, который выдаст готовый экземпляр.

К сожалению, Google решил, что они не хотят продвигать этот низкоуровневый подход API и предпочитают, чтобы разработчики использовали JDO или JPA, поэтому нет никакой доступной документации, кроме JavaDocs и любых примеров кода, которые вы можете найти, когда вы Google DatastoreService,

TL

Последние новости.. по крайней мере, я просто получаю это. Когда я загружал последний Java SDK для GAE, я заметил в примечаниях к выпуску, что "проблема 29: получение пакета Expose" была исправлена ​​в последней версии (v1.2.1). По сути, кажется, что у нас (я ищу ту же поддержку, что и кажется) может быть альтернатива на основе JDO, а не переходить на "низкоуровневый" API Datastore. Я только что скачал последнюю версию Java GAE SDK, поэтому у меня еще не было возможности что-либо протестировать, но я хотел дать вам быстрый ответ. Я опубликую все, что узнаю после того, как у меня будет возможность подтвердить это "исправление".

Пожалуйста, примите мои извинения, если я нарушил этикет Stackru, повторно опубликовав свой комментарий в качестве ответа, но я решил сделать это по двум причинам. Во-первых, потому что, хотя я снова решаю ту же проблему, ИМХО эта новая информация, по-видимому, дает совершенно другой "ответ" на проблему. И во-вторых, я был обеспокоен тем, что форма комментария может не привлечь ваше внимание, прежде чем вы потратите много времени на изучение первого ответа, который я предоставил.

В следующий раз я подумаю, прежде чем действовать.

TL

Одним из способов упростить "сделай сам" может быть использование параметризованных запросов:

   Query query = pm.newQuery(mytype.class);
   query.setFilter("field == autoParam");
   query.declareParameters("String autoParam");

   List<String> params = myListOfThingsFieldCanBeEqualTo;

   Set merged = new HashSet();
   for (String f : params) {
     merged.addAll(q.execute(f));
   }

Вы можете использовать метод содержит

String filters = "( :values.contains(field) )";
Query query = pm.newQuery(myType.class, filters);

Вопреки ответу Cletus, OR- IN работает, в любом случае, в более поздней версии App Engine.

Действительно, я обнаружил, что ИЛИ не работает в App Engine 1.3.0, который у меня был, но согласно Google App Engine - Запросы и индексы (тот же источник, упомянутый в его ответе),

Сущность должна соответствовать всем фильтрам, чтобы быть результатом. В строковом синтаксисе JDOQL вы можете разделить несколько фильтров с помощью || (логическое "или") и && (логическое "и"), хотя имейте в виду, что || может использоваться только тогда, когда все фильтры, которые он разделяет, имеют одинаковое имя поля. Другими словами, || допустимо только в тех случаях, когда фильтры, которые он разделяет, могут быть объединены в один фильтр contains().

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

Обновите App Engine до 1.3.4, и операционная система работает! Хотя с ограничением.

В любом случае, благодаря Cletus:)

Другие вопросы по тегам