GoogleAppEngine: 是否可以执行 GqlLike 查询?

其实很简单。在 SQL 中,如果我想在一个文本字段中搜索几个字符,我可以这样做:

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

App Engine 的文档没有提到如何实现这一点,但是这确实是一个足够常见的问题吗?

43359 次浏览

BigTable 是 AppEngine 的数据库后端,可以扩展到数百万条记录。由于这个原因,App Engine 将不允许您执行任何将导致表扫描的查询,因为对于一个填充良好的表来说,性能将非常糟糕。

换句话说,每个查询都必须使用索引。这就是为什么你只能做 =><查询。(实际上,您也可以执行 !=,但是 API 使用 ><查询的组合来执行此操作。)这也是为什么开发环境会监视所有的查询,并自动将任何缺少的索引添加到 index.yaml文件中。

没有办法为 LIKE查询建立索引,所以它根本不可用。

有一个更好的和更详细的解释 这个 Google IO 会议的手表。

i'm facing the same problem, but i found something on google app engine pages:

提示: 查询过滤器没有显式的方法只匹配字符串值的一部分,但是您可以使用不等式过滤器伪造前缀匹配:

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

This matches every MyModel entity with a string property prop that begins with the characters abc. The unicode string u"\ufffd" represents the largest possible Unicode character. When the property values are sorted in an index, the values that fall in this range are all of the values that begin with the given prefix.

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

maybe this could do the trick ;)

虽然 AppEngine 不支持 LIKE 查询,但是可以看一下属性 列表属性StringListProperty。当对这些属性进行相等性测试时,测试实际上将应用于所有列表成员,例如,如果值出现在列表中的任何位置,则应用于 list_property = value测试。

有时候,这个特性可以作为解决办法来使用,以避免类似查询的出现。例如,它使做 简单的文本搜索,如本文所述成为可能。

看看 Objectify 给你,它就像一个 Datastore 访问 API。这里有一个关于这个问题的常见问题,这里是答案

How do I do a like query (LIKE "foo%")
You can do something like a startWith, or endWith if you reverse the order when stored and searched. You do a range query with the starting value you want, and a value just above the one you want.

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

如果 LIKE '%text%'总是比较一个词或几个词(想想排列)和你的数据变化缓慢(缓慢意味着它不是过于昂贵-无论是价格和性能明智-创建和更新索引) ,那么关系索引实体(RIE)可能是答案。

是的,您必须构建额外的数据存储实体并适当地填充它。是的,有一些约束您必须处理(一个是 GAE 数据存储中的 list 属性的长度限制为5000)。但是搜索结果是闪电般的快。

有关详细信息,请参阅我的 使用 Java 和 Ojbectify 的 RIE用 Python 实现 RIE职位。

"Like" is often uses as a poor-man's substitute for text search. For text search, it is possible to use 嗖-AppEngine.

跟着这里: Init.py # 354“ > http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/search/abc0.py#354

It works!

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

App Engine 在1.7.0版中启动了通用 全文检索服务,支持数据存储。

Details in the announcement.

更多关于如何使用的信息: https://cloud.google.com/appengine/training/fts_intro/lesson2

您需要使用 搜寻服务来执行类似于 SQLLIKE的全文搜索查询。

Gaelyk provides domain specific language to perform more 用户友好的搜索查询. For example following snippet will find first ten books sorted from the latest ones with title containing fern and the genre exactly matching 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)之类的函数。

我使用 GAE Datastore 低级 JavaAPI 进行了测试,结果非常完美

    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);

一般来说,即使这是一篇老文章,生成‘ LIKE’或‘ ILIKE’的一种方法是收集来自‘ > =’查询的所有结果,然后循环生成 python (或 Java)中包含所需元素的结果。

假设你想过滤给定 q = ‘ 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)

不可能在数据存储应用程序引擎上进行类似的搜索,如果你需要在字符串中搜索一个单词,那么创建一个数组列表就可以做到这一点。

@Index
public ArrayList<String> searchName;

然后使用 objectify 在索引中搜索。

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

这将给你一个列表,包含所有的项目,包含世界你在搜索