Google App Engine: è possibile eseguire una query Gql LIKE?


123

Semplice davvero. In SQL, se voglio cercare un campo di testo per un paio di caratteri, posso fare:

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

La documentazione di App Engine non fa menzione di come ottenere questo risultato, ma sicuramente è un problema abbastanza comune?


3
Il problema continuo ruota attorno alle persone che cercano di utilizzare GAE Datastore come se fosse un database relazionale / ~ SQL. Con l'introduzione di GQL da parte di Google, porta le persone a pensare in termini di sistemi SQL. Tuttavia, capisco che Google sta cercando di rendere la transizione per tutti molto più semplice, anche se non sono sicuro che questo sia l'approccio giusto.
Fuentesjr

Risposte:


81

BigTable, che è il back-end del database per App Engine, scalerà a milioni di record. Per questo motivo, App Engine non ti consentirà di eseguire query che risulteranno in una scansione della tabella, poiché le prestazioni sarebbero terribili per una tabella ben popolata.

In altre parole, ogni query deve utilizzare un indice. Questo è il motivo per cui si può fare solo =, >e <le query. (In effetti puoi anche farlo, !=ma l'API lo fa usando una combinazione di >e <query.) Questo è anche il motivo per cui l'ambiente di sviluppo monitora tutte le query che fai e aggiunge automaticamente eventuali indici mancanti al tuo index.yamlfile.

Non c'è modo di indicizzare una LIKEquery, quindi semplicemente non è disponibile.

Guarda questa sessione di Google IO per una spiegazione molto migliore e più dettagliata di questo.


77

Sto affrontando lo stesso problema, ma ho trovato qualcosa sulle pagine del motore dell'app Google:

Suggerimento: i filtri di query non hanno un modo esplicito per abbinare solo una parte di un valore di stringa, ma puoi simulare una corrispondenza di prefisso utilizzando i filtri di disuguaglianza:

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

Questo corrisponde a ogni entità MyModel con un prop di proprietà stringa che inizia con i caratteri abc. La stringa Unicode u "\ ufffd" rappresenta il carattere Unicode più grande possibile. Quando i valori delle proprietà vengono ordinati in un indice, i valori che rientrano in questo intervallo sono tutti i valori che iniziano con il prefisso specificato.

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

forse questo potrebbe fare il trucco;)


6
+1 Anche se vale la pena sottolineare che è sensibile al maiuscolo / minuscolo. Fortunatamente i dati nel campo che sto interrogando vengono convertiti in minuscolo prima della memorizzazione.
Cuga

12

Anche se App Engine non supporta le query LIKE, dai un'occhiata alle proprietà ListProperty e StringListProperty . Quando viene eseguito un test di uguaglianza su queste proprietà, il test verrà effettivamente applicato a tutti i membri dell'elenco, ad esempio, list_property = valueverifica se il valore appare in un punto qualsiasi dell'elenco.

A volte questa funzionalità potrebbe essere utilizzata come soluzione alternativa alla mancanza di query LIKE. Ad esempio, consente di eseguire semplici ricerche di testo, come descritto in questo post .


3
il post non esiste più
mwm

9

È necessario utilizzare il servizio di ricerca per eseguire query di ricerca full-text simili a SQL LIKE.

Gaelyk fornisce un linguaggio specifico del dominio per eseguire query di ricerca più intuitive . Ad esempio, il seguente snippet troverà i primi dieci libri ordinati dagli ultimi con il titolo contenente fern e il genere che corrisponde esattamente 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 è scritto come operatore di corrispondenza di Groovy =~. Supporta anche funzioni distance(geopoint(lat, lon), location)come.



3

Dai un'occhiata a Objectify qui , è come un'API di accesso al datastore. C'è una FAQ con questa domanda specifica, ecco la risposta

Come faccio a eseguire una query simile (LIKE "foo%")
Puoi fare qualcosa come startWith o endWith se inverti l'ordine quando memorizzato e cercato. Esegui una query di intervallo con il valore iniziale che desideri e un valore appena sopra quello che desideri.

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

1
cercherà "inizia con" non "Contiene".
Hardik Patel

1

Segui qui: init.py # 354 "> http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/search/ init .py # 354

Funziona!

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

L'ho testato con l'API Java di basso livello di GAE Datastore. Me e funziona perfettamente

    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
questo funziona per il prefisso, ma cosa succede se voglio trovare una corrispondenza dalla fine della stringa? Ad esempio, voglio cercare abc in sdfdsabc, quindi dovrebbe restituire sdfdsabc
user1930106

1

In generale, anche se questo è un vecchio post, un modo per produrre un "MI PIACE" o "ILIKE" consiste nel raccogliere tutti i risultati da una query "> =", quindi i risultati del ciclo in python (o Java) per gli elementi che contengono ciò che si stai cercando.

Supponiamo che tu voglia filtrare gli utenti con 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

Non è possibile eseguire una ricerca LIKE sul motore dell'app del datastore, tuttavia la creazione di un Arraylist farebbe il trucco se è necessario cercare una parola in una stringa.

@Index
    public ArrayList<String> searchName;

e quindi per cercare nell'indice utilizzando oggettivare.

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

e questo ti darà un elenco con tutti gli elementi che contengono il mondo che hai fatto nella ricerca


0

Se il LIKE '%text%'confronto è sempre con una parola o poche (pensa alle permutazioni) e i tuoi dati cambiano lentamente (lentamente significa che non è proibitivo - sia in termini di prezzo che di prestazioni - creare e aggiornare gli indici), allora Relation Index Entity (RIE) potrebbe essere la risposta.

Sì, dovrai creare un'entità del datastore aggiuntiva e popolarla in modo appropriato. Sì, ci sono alcuni vincoli su cui devi giocare (uno è il limite di 5000 sulla lunghezza della proprietà dell'elenco nel datastore GAE). Ma le ricerche che ne derivano sono velocissime.

Per i dettagli vedere i miei post RIE con Java e Ojbectify e RIE con Python .


0

"Mi piace" viene spesso utilizzato come sostituto dei poveri per la ricerca di testo. Per la ricerca di testo, è possibile utilizzare Whoosh-AppEngine .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.