Google App Engine: чи можна зробити запит GQl LIKE?


123

Простий справді. У SQL, якщо я хочу шукати текстове поле для пари символів, я можу зробити:

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

У документації для App Engine не згадується, як цього досягти, але, безумовно, це досить поширена проблема?


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

Відповіді:


81

BigTable, який є заднім кінцем баз даних для App Engine, збільшуватиме мільйони записів. Завдяки цьому App Engine не дозволить вам робити будь-який запит, який призведе до сканування таблиці, оскільки продуктивність буде жахливою для добре заселеної таблиці.

Іншими словами, кожен запит повинен використовувати індекс. Саме тому ви можете тільки зробити =, >і <запити. (Насправді ви також можете це зробити, !=але API робить це за допомогою комбінації a >- <запитів.) Ось чому середовище розробки моніторить усі запити, які ви виконуєте, і автоматично додає будь-які відсутні індекси до вашого 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. Рядок unicode u "\ ufffd" являє собою найбільший можливий символ Unicode. Коли значення властивостей сортуються за індексом, значення, що потрапляють у цей діапазон, - це всі значення, що починаються із заданого префікса.

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

можливо, це могло б зробити трюк;)


6
+1 Того варто зазначити, що це враховує регістри. На щастя, дані в запитуваному полі перетворюються в малі регістри перед зберіганням.
Cuga

12

Altough App Engine не підтримує LIKE запити, подивіться на властивості ListProperty і StringListProperty . Коли для цих властивостей робиться тест на рівність, тест буде фактично застосований до всіх учасників списку, наприклад, list_property = valueтестів, якщо значення з’являється в будь-якому місці списку.

Іноді ця функція може бути використана як спосіб вирішення відсутності запитів LIKE. Наприклад, це дає можливість простого пошуку тексту, як описано в цій публікації .


3
повідомлення вже не існує
mwm

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
}

Мовляв, написано як оператор сірників Groovy =~. Він також підтримує такі функції distance(geopoint(lat, lon), location).



3

Подивіться на Objectify тут , це як API доступу до Datastore. З цим питанням є FAQ, ось відповідь

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

String start = "foo";
    ... = ofy.query(MyEntity.class).filter("field >=", start).filter("field <", start + "\uFFFD");

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(...)

1

Я перевірив це за допомогою Java API API низького рівня GAE. Я і чудово працює

    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)

1

Неможливо здійснити пошук LIKE в двигуні додатків для зберігання даних, але коли-небудь створення Arraylist зробить трюк, якщо вам потрібно шукати слово в рядку.

@Index
    public ArrayList<String> searchName;

а потім шукати в індексі за допомогою об’єктиву.

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

і це дасть вам список усіх елементів, які містять світ, який ви зробили під час пошуку


0

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

Так, вам доведеться створити додатковий об'єкт сховища даних та заповнити його відповідним чином. Так, є деякі обмеження, з якими вам доведеться обійтись (один - 5000 обмежень щодо довжини властивості списку в сховищі даних GAE). Але отримані пошуки блискавично проходять.

Детальніше дивіться мої RIE з Java та Ojbectify та RIE з повідомленнями Python .


0

"Like" часто використовується як заміна чоловіка для пошуку тексту. Для пошуку тексту можна використовувати Whoosh-AppEngine .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.