Google App Engine: можно ли выполнить запрос Gql LIKE?

123

На самом деле простой. В SQL, если я хочу найти в текстовом поле пару символов, я могу:

SELECT blah FROM blah WHERE blah LIKE '%text%'

В документации по App Engine не упоминается, как этого добиться, но разве это достаточно распространенная проблема?

littlecharva
источник
3
Продолжающаяся проблема вращается вокруг людей, пытающихся использовать GAE Datastore, как если бы это была реляционная база данных / ~ SQL. Благодаря тому, что Google представил GQL, он еще больше побуждает людей думать о системах SQL. Однако я понимаю, что Google пытается упростить переход для всех, хотя я не уверен, что это правильный подход.
fuentesjr,

Ответы:

81

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

Другими словами, каждый запрос должен использовать индекс. Именно поэтому вы можете только сделать =, >и <запросы. (На самом деле вы можете сделать , !=но API делает это , используя аа комбинации >и <запросов.) Это также почему среда разработки отслеживает все запросы вы делаете , и автоматически добавляет недостающие индексы в свой index.yamlфайл.

LIKEНевозможно индексировать запрос, поэтому он просто недоступен.

Посмотрите этот сеанс Google IO, чтобы получить более подробное и лучшее объяснение этого.

Дэйв Уэбб
источник
77

У меня та же проблема, но я нашел что-то на страницах движка приложений Google:

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

db.GqlQuery("SELECT * FROM MyModel WHERE prop >= :1 AND prop < :2",
            "abc",
            u"abc" + u"\ufffd")

Это соответствует каждой сущности MyModel со строковым свойством свойства, которое начинается с символов abc. Строка Юникода u "\ ufffd" представляет собой максимально возможный символ Юникода. Когда значения свойств сортируются в индексе, значения, попадающие в этот диапазон, - это все значения, начинающиеся с данного префикса.

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

может быть, это поможет;)

solidsnack
источник
6
+1 Стоит отметить, что здесь учитывается регистр. К счастью, данные в запрашиваемом поле перед сохранением преобразуются в нижний регистр.
Cuga 02
12

Хотя App Engine не поддерживает запросы LIKE, ознакомьтесь со свойствами ListProperty и StringListProperty . Когда проверка на равенство выполняется для этих свойств, проверка будет фактически применяться ко всем членам списка, например, list_property = valueпроверяет, появляется ли значение где-нибудь в списке.

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

jbochi
источник
3
пост больше не существует
mwm 08
9

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

Gaelyk предоставляет язык для конкретной предметной области для выполнения более удобных поисковых запросов . Например, следующий фрагмент найдет первые десять книг, отсортированных от последних, с указанием названия fern и точно совпадающим жанром thriller:

def documents = search.search {
    select all from books
    sort desc by published, SearchApiLimits.MINIMUM_DATE_VALUE
    where title =~ 'fern'
    and genre =  'thriller'
    limit 10
}

Like записывается как оператор сопоставления Groovy =~. Он также поддерживает такие функции distance(geopoint(lat, lon), location).

Musketyr
источник
3

Взгляните на Objectify здесь , это похоже на API доступа к хранилищу данных. Именно с этим вопросом есть FAQ, вот ответ

Как мне сделать подобный запрос (LIKE "foo%")
Вы можете сделать что-то вроде startWith или endWith, если вы измените порядок при сохранении и поиске. Вы выполняете запрос диапазона с желаемым начальным значением и значением чуть выше того, которое вам нужно.

String start = "foo";
    ... = ofy.query(MyEntity.class).filter("field >=", start).filter("field <", start + "\uFFFD");
fernandohur
источник
1
он будет искать «начинается с», а не «содержит».
Hardik Patel
1

Просто следуйте здесь: init.py # 354 "> http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/search/ init .py # 354

Оно работает!

class Article(search.SearchableModel):
    text = db.TextProperty()
    ...

  article = Article(text=...)
  article.save()

To search the full text index, use the SearchableModel.all() method to get an
instance of SearchableModel.Query, which subclasses db.Query. Use its search()
method to provide a search query, in addition to any other filters or sort
orders, e.g.:

  query = article.all().search('a search query').filter(...).order(...)
gzerone
источник
1

Я тестировал это с помощью низкоуровневого Java API GAE Datastore. У меня и работает отлично

    Query q = new Query(Directorio.class.getSimpleName());

    Filter filterNombreGreater = new FilterPredicate("nombre", FilterOperator.GREATER_THAN_OR_EQUAL, query);
    Filter filterNombreLess = new FilterPredicate("nombre", FilterOperator.LESS_THAN, query+"\uFFFD");
    Filter filterNombre =  CompositeFilterOperator.and(filterNombreGreater, filterNombreLess);

    q.setFilter(filter);
Эди Агирре
источник
1
это работает для префикса, но что, если я хочу найти совпадение с конца строки? Например, я хочу найти abc в sdfdsabc, тогда он должен вернуть sdfdsabc
user1930106
1

В общем, даже несмотря на то, что это старый пост, способ создать 'LIKE' или 'ILIKE' состоит в том, чтобы собрать все результаты из запроса '> =', а затем цикл результатов в python (или Java) для элементов, содержащих то, что вы ищем.

Допустим, вы хотите отфильтровать пользователей с учетом aq = 'luigi'

users = []
qry = self.user_model.query(ndb.OR(self.user_model.name >= q.lower(),self.user_model.email >= q.lower(),self.user_model.username >= q.lower()))

for _qry in qry:
 if q.lower() in _qry.name.lower() or q.lower() in _qry.email.lower() or q.lower() in _qry.username.lower():
      users.append(_qry)
chuycepeda
источник
1

Невозможно выполнить поиск LIKE на движке приложения хранилища данных, однако создание Arraylist поможет, если вам нужно найти слово в строке.

@Index
    public ArrayList<String> searchName;

а затем выполнить поиск в индексе с помощью objectify.

List<Profiles> list1 = ofy().load().type(Profiles.class).filter("searchName =",search).list();

и это даст вам список со всеми элементами, которые содержат мир, который вы искали.

Хосе Салас
источник
0

Если LIKE '%text%'всегда сравнивается с одним словом или несколькими (подумайте о перестановках) и ваши данные изменяются медленно (медленно означает, что создание и обновление индексов не слишком дорого - как с точки зрения цены, так и с точки зрения производительности)), тогда объект индекса отношения (RIE) может быть ответом.

Да, вам придется создать дополнительный объект хранилища данных и соответствующим образом заполнить его. Да, есть некоторые ограничения, с которыми вам придется поиграть (одно из них - ограничение в 5000 на длину свойства списка в хранилище данных GAE). Но поисковые запросы происходят молниеносно.

Подробнее см. Мои сообщения RIE с Java и Ojbectify и RIE с Python .

topchef
источник
0

"Нравится" часто используется бедняками вместо поиска текста. Для текстового поиска можно использовать Whoosh-AppEngine .

Амит
источник