Google App Engine: czy można wykonać zapytanie Gql LIKE?


123

Naprawdę proste. W SQL, jeśli chcę przeszukać pole tekstowe dla kilku znaków, mogę zrobić:

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

Dokumentacja App Engine nie wspomina, jak to osiągnąć, ale na pewno jest to dość powszechny problem?


3
Ciągły problem dotyczy ludzi, którzy próbują używać GAE Datastore tak, jakby była to relacyjna / ~ SQL baza danych. Wprowadzenie GQL przez Google dodatkowo prowadzi ludzi do myślenia w kategoriach systemów SQL. Rozumiem jednak, że Google stara się znacznie ułatwić przejście dla wszystkich, mimo że nie jestem pewien, czy jest to właściwe podejście.
fuentesjr

Odpowiedzi:


81

BigTable, który jest zapleczem bazy danych dla App Engine, będzie skalowany do milionów rekordów. Z tego powodu App Engine nie pozwoli Ci wykonać żadnego zapytania, które spowoduje skanowanie tabeli, ponieważ wydajność byłaby straszna dla dobrze zapełnionej tabeli.

Innymi słowy, każde zapytanie musi używać indeksu. To dlatego można zrobić tylko =, >i <zapytań. (W rzeczywistości możesz również to zrobić, !=ale API robi to za pomocą kombinacji zapytań >i <). Z tego powodu środowisko programistyczne monitoruje wszystkie zapytania, które wykonujesz i automatycznie dodaje wszelkie brakujące indeksy do index.yamlpliku.

Nie ma możliwości indeksowania LIKEzapytania, więc jest po prostu niedostępne.

Obejrzyj tę sesję Google IO, aby uzyskać znacznie lepsze i bardziej szczegółowe wyjaśnienie tego.


77

mam ten sam problem, ale znalazłem coś na stronach silnika aplikacji Google:

Wskazówka: filtry zapytań nie mają jawnego sposobu dopasowania tylko części wartości ciągu, ale możesz sfałszować dopasowanie prefiksu za pomocą filtrów nierówności:

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

To dopasowuje każdą jednostkę MyModel do właściwości string, która zaczyna się od znaków abc. Ciąg znaków Unicode u "\ ufffd" reprezentuje największy możliwy znak Unicode. Gdy wartości właściwości są sortowane w indeksie, wszystkie wartości należące do tego zakresu są wartościami rozpoczynającymi się od danego przedrostka.

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

może to załatwi sprawę;)


6
+1 Warto jednak zaznaczyć, że rozróżniana jest wielkość liter. Na szczęście dane w polu, którego dotyczy zapytanie, są konwertowane na małe litery przed zapisaniem.
Cuga

12

Chociaż App Engine nie obsługuje zapytań LIKE, spójrz na właściwości ListProperty i StringListProperty . Gdy dla tych właściwości zostanie wykonany test równości, zostanie on faktycznie zastosowany do wszystkich elementów listy, np. list_property = valueTesty, jeśli wartość pojawi się w dowolnym miejscu na liście.

Czasami ta funkcja może być używana jako obejście braku zapytań LIKE. Na przykład umożliwia proste wyszukiwanie tekstu, jak opisano w tym poście .


3
post już nie istnieje
mwm

9

Aby wykonywać zapytania wyszukiwania pełnotekstowego podobne do SQL, musisz użyć usługi wyszukiwania LIKE.

Gaelyk zapewnia język specyficzny dla domeny, aby wykonywać bardziej przyjazne dla użytkownika zapytania . Na przykład poniższy fragment spowoduje znalezienie pierwszych dziesięciu książek posortowanych od najnowszych z tytułem zawierającym fern i dokładnie pasującym gatunkiem 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 jest zapisane jako operator dopasowania Groovy'ego =~. Obsługuje również takie funkcje distance(geopoint(lat, lon), location).



3

Spójrz na Objectify tutaj , to jest jak Access API Datastore. Znajduje się tam często zadawane pytania dotyczące tego pytania, oto odpowiedź

Jak wykonać podobne zapytanie (LIKE "foo%")
Możesz zrobić coś takiego jak startWith lub endWith, jeśli odwrócisz kolejność zapisywania i wyszukiwania. Wykonujesz zapytanie o zakres z żądaną wartością początkową i wartością tuż powyżej żądanej.

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

1
wyszuka „zaczyna się od”, a nie „zawiera”.
Hardik Patel

1

Po prostu wykonaj następujące czynności: init.py # 354 "> http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/search/ init .py # 354

To działa!

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

Przetestowałem to z niskopoziomowym API Java GAE Datastore. Ja i działa idealnie

    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
działa to dla prefiksu, ale co jeśli chcę dopasować od końca ciągu? Na przykład - chcę wyszukać abc w sdfdsabc, to powinno zwrócić sdfdsabc
user1930106

1

Ogólnie, mimo że jest to stary post, sposobem na utworzenie „LIKE” lub „ILIKE” jest zebranie wszystkich wyników z zapytania „> =”, a następnie zapętlenie wyników w pythonie (lub Javie) dla elementów zawierających to, co szukasz.

Powiedzmy, że chcesz odfiltrować użytkowników, którym podano 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

Nie jest możliwe wyszukanie LIKE w silniku aplikacji datastore, jakkolwiek utworzenie tablicy Arraylist załatwiłoby sprawę, gdyby trzeba było wyszukać słowo w ciągu.

@Index
    public ArrayList<String> searchName;

a następnie przeszukać indeks przy użyciu Objectify.

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

a to da ci listę wszystkich elementów, które zawierają świat, który zrobiłeś podczas wyszukiwania


0

Jeśli LIKE '%text%'zawsze porównuje się do jednego lub kilku słów (pomyśl o permutacjach), a Twoje dane zmieniają się powoli (powoli oznacza, że ​​tworzenie i aktualizowanie indeksów nie jest zbyt drogie - zarówno pod względem ceny, jak i wydajności), wówczas Relation Index Entity (RIE) może być odpowiedzią.

Tak, będziesz musiał zbudować dodatkową encję magazynu danych i odpowiednio ją wypełnić. Tak, istnieją pewne ograniczenia, z którymi będziesz musiał się bawić (jeden to 5000 limit długości właściwości listy w magazynie danych GAE). Ale wynikające z tego wyszukiwania są błyskawiczne.

Aby uzyskać szczegółowe informacje, zobacz moje RIE z Javą i Ojbectify oraz RIE z Pythonem .


0

„Lubię” jest często używane jako substytut wyszukiwania tekstu przez biedaka. Do wyszukiwania tekstowego można użyć Whoosh-AppEngine .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.