查询重复属性开始于

时间:2013-08-08 22:43:21

标签: google-app-engine google-cloud-datastore app-engine-ndb

假设我有一个电影数据库,您可以按标题搜索。

我有一个Movie模型,如下所示(简化)

class Movie(ndb.Model):
    name = ndb.StringProperty(required=True)
    queryName = ndb.ComputedProperty(lambda self: [w.lower() for w in self.name.split()], repeated=True)

    @staticmethod
    def parent_key():
        return ndb.Key(Movie, 'parent')

queryName只是Movie.name中单词的小写列表。 parent_key()仅适用于查询

如果我正在搜索电影Forest Gump,我希望它能够显示以下搜索字词(以及更多,这些只是示例)

  1. 'fo' - 'forest'以'fo'开头
  2. 'gu' - 'gump'以'gu'开头
  3. 'gu fo' - 'forest'以'fo'开头,'gump'以'gu'开头
  4. 我可以使用类似于以下内容的查询轻松获得前两个

    movies = Movie\
        .query(ancestor=Movie.parent_key())\
        .filter(Movie.queryName >= x)\
        .filter(Movie.queryName < x + u'\ufffd')\
        .feth(10)
    

    其中x是'fo'或'gu'。同样,这只是一个不是我的实际代码的查询。那是后来的事。如果我在上面的查询上展开一点来寻找两个单词,我认为我可以做类似下面的事情,但它不起作用。

    movies = Movie\
        .query(ancestor=Movie.parent_key())\
        .filter(Movie.queryName >= 'fo')\
        .filter(Movie.queryName < 'fo' + u'\ufffd')\
        .filter(Movie.queryName >= 'gu')\
        .filter(Movie.queryName < 'gu' + u'\ufffd')\
        .feth(10)
    

    现在,这不起作用,因为它正在queryName查看它是否有任何以'fo'开头并以'gu'开头的项目。由于列表中的单个项目永远不会成立,因此查询不会返回任何内容。

    问题是,如何查询Movies哪个queryName的项目以'fo'开头? AND 以'gu'开头的项目?

    实际代码:

    class MovieSearchHandler(BaseHandler):
        def get(self):
            q = self.request.get('q')
    
            if q:
                q = q.replace('&', '&amp;').lower()
                filters = self.create_filter(*q.split())
    
                if filters:
                    movies = Movie\
                        .query(ancestor=Movie.parent_key())\
                        .filter(*filters)\
                        .fetch(10)
    
                    return self.write_json([{'id': m.movieId, 'name': m.name} for m in movies])
    
            return self.write_json([])
    
        def create_filter(self, *args):
            filters = []
    
            if args:
                for prefix in args:
                    filters.append(Movie.queryName >= prefix)
                    filters.append(Movie.queryName < prefix + u'\ufffd')
    
            return filters
    

    更新

    我目前的解决方案是

    class MovieSearchHandler(BaseHandler):
        def get(self):
            q = self.request.get('q')
    
            if q:
                q = q.replace('&', '&amp;').lower().split()
                movieFilter, reducable = self.create_filter(*q)
    
                if movieFilter:
                    movies = Movie\
                        .query(ancestor=Movie.parent_key())\
                        .filter(movieFilter)\
                        .fetch(None if reducable else 10)
    
                    if reducable:
                        movies = self.reduce(movies, q)
    
                    return self.write_json([{'id': m.movieId, 'name': m.name} for m in movies])
    
            return self.write_json([])
    
        def create_filter(self, *args):
            if args:
                if len(args) == 1:
                    prefix = args[0]
                    return ndb.AND(Movie.queryName >= prefix, Movie.queryName < prefix + u'\ufffd'), False
    
                ands = [ndb.AND(Movie.queryName >= prefix, Movie.queryName < prefix + u'\ufffd')
                        for prefix in args]
    
                return ndb.OR(*ands), True
    
            return None, False
    
        def reduce(self, movies, terms):
            reducedMovies = []
    
            for m in movies:
                if len(reducedMovies) >= 10:
                    return reducedMovies
                if all(any(n.startswith(t) for n in m.queryName) for t in terms):
                    reducedMovies.append(m)
    
            return reducedMovies
    

    仍在寻找更好的东西

    由于

0 个答案:

没有答案