谷歌应用引擎:是否可以执行Gql LIKE查询?

125

很简单。在SQL中,如果我想要搜索文本字段中的一些字符,可以这样做:

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

App Engine的文档中没有提到如何解决这个问题,但是这肯定是一个相当普遍的问题吧?


3
持续存在的问题是人们试图将GAE Datastore当作一个关系/SQL数据库来使用。谷歌推出GQL进一步让人们以SQL系统的方式思考。但我理解谷歌正尝试让每个人的转变更容易,尽管我不确定这是否是正确的方法。 - fuentesjr
12个回答

82

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

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

无法为LIKE查询创建索引,因此无法使用LIKE查询。

观看此Google IO会话,以获得更好、更详细的解释。


77
我也遇到了同样的问题,但在谷歌应用引擎页面上找到了一些有用的信息:
提示:查询过滤器没有明确的方法来匹配字符串值的一部分,但您可以使用不等式过滤器来模拟前缀匹配。
db.GqlQuery("SELECT * FROM MyModel WHERE prop >= :1 AND prop < :2",
            "abc",
            u"abc" + u"\ufffd")

这将匹配所有具有以字符abc开头的字符串属性prop的MyModel实体。Unicode字符串u"\ufffd"表示最大可能的Unicode字符。当属性值在索引中排序时,落在此范围内的值都是以给定前缀开头的所有值。

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

也许这个可以解决问题 ;)


6
+1 虽然值得指出这是区分大小写的。幸运的是,我查询的字段中的数据在存储之前已转换为小写。 - Cuga

12
虽然App Engine不支持LIKE查询,但请查看ListPropertyStringListProperty属性。当对这些属性执行相等性测试时,测试实际上将应用于所有列表成员,例如,list_property = value测试值是否出现在列表中的任何位置。
有时,此功能可能会被用作解决缺少LIKE查询的方法。例如,它使得可以进行简单的文本搜索,正如在这篇文章中所描述的那样。

4
这篇文章已经不存在了。 - 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
}

Like操作符在Groovy中被称为匹配操作符=~。它还支持函数,例如distance(geopoint(lat, lon), location)


4

3
请查看Objectify 这里,它类似于Datastore访问API。有一个特定的FAQ与此问题,以下是答案:
如何执行类似查询(LIKE“foo%”) 您可以执行类似于startWith或endWith的操作,如果在存储和搜索时反转顺序,则可以执行此操作。您可以使用所需的起始值进行范围查询,并使用略高于所需值的值。
String start = "foo";
    ... = ofy.query(MyEntity.class).filter("field >=", start).filter("field <", start + "\uFFFD");

1
它将搜索“以……开头”,而不是“包含”。 - Hardik Patel

1
通常情况下,即使这是一篇老帖子,生成“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)

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

在数据存储应用程序引擎上无法进行LIKE搜索,如果您需要在字符串中搜索单词,则创建ArrayList将会起到作用。

@Index
    public ArrayList<String> searchName;

然后使用Objectify在索引中搜索。
List<Profiles> list1 = ofy().load().type(Profiles.class).filter("searchName =",search).list();

这将为您提供一个包含搜索关键词的所有项目的列表。

1

我使用GAE Datastore低级Java API进行了测试。它与我的工作完美匹配。

    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
这适用于前缀,但如果我想从字符串的末尾匹配怎么办? 例如 - 我想在sdfdsabc中搜索abc,那么它应该返回sdfdsabc。 - user1930106

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接