Хранилище данных 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:)