2008-09-06 26 views
111

Simple realmente. En SQL, si quiero buscar un campo de texto para un par de caracteres, lo que puedo hacer:Google App Engine: ¿es posible hacer una consulta Gql LIKE?

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

La documentación de App Engine no hace mención de cómo lograr esto, pero seguro que es un problema bastante común?

+4

1. Buena pregunta con buenas respuestas –

+3

El problema continuo gira en torno a las personas que intentan utilizar GAE Datastore como si fuera una base de datos Relational/~ SQL. Al introducir Google GQL, lleva a las personas a pensar en términos de sistemas SQL. Sin embargo, entiendo que Google está tratando de hacer la transición para todos mucho más fácil, aunque no estoy seguro de que este sea el enfoque correcto. – fuentesjr

Respuesta

74

BigTable, que es el back-end de la base de datos para App Engine, se escalará a millones de registros. Debido a esto, App Engine no te permitirá realizar ninguna consulta que genere un escaneo de tabla, ya que el rendimiento sería espantoso para una tabla bien poblada.

En otras palabras, cada consulta debe usar un índice. Es por eso que solo puede hacer consultas =, > y <. (De hecho, también puede hacer != pero la API hace esto usando una combinación de consultas > y <). Esta también es la razón por la que el entorno de desarrollo monitorea todas las consultas que hace y agrega automáticamente los índices faltantes a su archivo index.yaml.

No hay forma de indexar para una consulta LIKE por lo que simplemente no está disponible.

Ten un reloj de this Google IO session para una explicación mucho mejor y más detallada de esto.

72

que estoy enfrentando el mismo problema, pero he encontrado algo en las páginas del motor de aplicación de Google:

Consejo: Los filtros de consulta no tienen una forma explícita para que coincida con sólo una parte de un valor de cadena, pero se puede falsificar una prefijo por el uso de filtros de desigualdad:

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

Esto coincide con todas las entidades MyModel con un puntal propiedad de cadena que comienza con los caracteres ABC. La cadena unicode u "\ ufffd" representa el máximo carácter Unicode posible. Cuando los valores de las propiedades se ordenan en un índice, los valores que caen en este rango son todos los valores que comienzan con el prefijo dado.

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

tal vez esto podría hacer el truco;)

+6

+1 Aunque vale la pena señalar que esto distingue entre mayúsculas y minúsculas. Afortunadamente, los datos en el campo que estoy consultando se convierten en minúsculas antes de almacenarlos. – Cuga

12

Altough App Engine no admite COMO consultas, echar un vistazo a las propiedades y ListPropertyStringListProperty. Cuando se realiza una prueba de igualdad en estas propiedades, la prueba se aplicará realmente a todos los miembros de la lista, por ejemplo, list_property = value si el valor aparece en alguna parte de la lista.

A veces, esta característica se puede utilizar como una solución a la falta de consultas LIKE. Por ejemplo, hace posible hacer simple text search, as described on this post.

+0

la publicación ya no existe – mwm

3

Eche un vistazo a Objectify here, es como una API de acceso al almacén de datos. Hay un FAQ con esta pregunta en concreto, aquí está la respuesta

¿Cómo puedo hacer una consulta como (como "foo%")
se puede hacer algo como un startWith o ENDWITH si invierte el orden cuando está almacenado y buscado. Hace una consulta de rango con el valor inicial que desea y un valor justo por encima del que desea.

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

buscará "comienza por" y no "contiene". –

0

Si el LIKE '%text%' siempre se compara con una palabra o unos pocos (pensar permutaciones) y sus datos cambian lentamente (lentamente significa que no es prohibitivamente caro - tanto en cuanto al precio y en cuanto al rendimiento - para crear y índices de actualizaciones), entonces la entidad del índice de relación (RIE) puede ser la respuesta.

Sí, tendrá que crear una entidad de almacenamiento de datos adicional y completarla adecuadamente. Sí, hay algunas restricciones que tendrá que jugar (una es el límite de 5000 en la longitud de la propiedad de la lista en el almacén de datos de GAE). Pero las búsquedas resultantes son muy rápidas.

Para obtener más información, consulte mis publicaciones RIE with Java and Ojbectify y RIE with Python.

0

"Me gusta" a menudo se usa como sustituto de un hombre pobre para la búsqueda de texto. Para la búsqueda de texto, es posible usar Whoosh-AppEngine.

1

Sólo tiene que seguir aquí: init.py # 354" > http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/search/ init. py # 354

funciona!

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

Es necesario utilizar search service para realizar consultas de búsqueda de texto completo similares a SQL LIKE.

Gaelyk proporciona un lenguaje específico dominio para realizar más user friendly search queries. Por ejemplo siguiente fragmento encontrará primeros diez libros ordenados desde los más recientes con el título que contiene fern y el género que coincide exactamente 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 
} 

Como se escribe como operador de partido del maravilloso =~. También es compatible con funciones como distance(geopoint(lat, lon), location).

1

He probado esto con la API Java de bajo nivel de GAE Datastore. Yo y funciona perfectamente

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

esto funciona para el prefijo, pero ¿y si quiero unirme desde el final de la cadena? Por ejemplo, quiero buscar abc en sdfdsabc, entonces debería devolver sdfdsabc – user1930106

1

En general, a pesar de que este es un mensaje de edad, una manera de producir un 'me gusta' o 'ILIKE' es reunir todos los resultados de una consulta '> =', entonces los resultados de bucle en python (o Java) para elementos que contienen lo que estás buscando.

Digamos que desea filtrar los usuarios dados 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

No es posible hacer una búsqueda como en el motor de aplicación de almacén de datos, cómo cada vez la creación de un ArrayList que hacer el truco si es necesario para buscar una palabra en una cadena.

@Index 
    public ArrayList<String> searchName; 

y luego buscar en el índice usando objectify.

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

y esto le dará una lista con todos los elementos que contengan el mundo que hizo en la búsqueda