【问题标题】:Filter and sort music info on Google App Engine在 Google App Engine 上过滤和排序音乐信息
【发布时间】:2010-11-15 21:13:19
【问题描述】:

我很喜欢在 GAE 上构建几个简单的应用程序,但现在我对如何在应用程序引擎上构建音乐收藏管理器感到困惑。简而言之,我不知道如何在对另一个属性进行排序时过滤多个属性。

假设核心模型是一个包含多个属性的专辑,包括:

  • 标题
  • 艺术家
  • 标签
  • 出版年份
  • 类型
  • 长度
  • 曲目名称列表
  • 心情列表
  • 插入数据库的日期时间

我们还假设我想使用这些属性过滤整个集合,然后按以下之一对结果进行排序:

  • 出版年份
  • 专辑长度
  • 艺术家姓名
  • 信息添加到数据库时

如果不遇到爆炸性索引难题,我不知道该怎么做。具体来说,我想做这样的事情:

Albums.all().filter('publication_year <', 1980).order('artist_name')

我知道这是不可能的,但有什么解决方法?

这似乎是一种相当通用的应用程序。音乐专辑可以是餐馆、酒瓶或酒店。我有一组具有描述性属性的项目,我想对其进行过滤和排序。

是否存在我忽略的最佳实践数据模型设计?有什么建议吗?

【问题讨论】:

    标签: python google-app-engine django-models model


    【解决方案1】:

    由于存储成本低廉,您可以创建自己的基于 ListProperty 的索引文件,其中的 key_names 反映了排序标准。

    class album_pubyear_List(db.Model):
        words = db.StringListProperty()
    
    class album_length_List(db.Model):
        words = db.StringListProperty()
    
    class album_artist_List(db.Model):
        words = db.StringListProperty()
    
    class Album(db.Model):
        blah...
    
        def save(self):
            super(Album, self).save()
    
            # you could do this at save time or batch it and do
            # it with a cronjob or taskqueue
    
            words = []
    
            for field in ["title", "artist", "label", "genre", ...]:
                words.append("%s:%s" %(field, getattr(self, field)))
    
            word_records = []
            now = repr(time.time())
            word_records.append(album_pubyear_List(parent=self, key_name="%s_%s" %(self.pubyear, now)), words=words)
            word_records.append(album_length_List(parent=self, key_name="%s_%s" %(self.album_length, now)), words=words)
            word_records.append(album_artist_List(parent=self, key_name="%s_%s" %(self.artist_name, now)), words=words)
            db.put(word_records)
    

    现在是时候搜索你创建一个合适的 WHERE 子句并调用合适的模型

    where = "WHERE words = " + "%s:%s" %(field-a, value-a) + " AND " + "%s:%s" %(field-b, value-b) etc.
    aModel = "album_pubyear_List" # or anyone of the other key_name sorted wordlist models
    
    indexes = db.GqlQuery("""SELECT __key__ from %s %s""" %(aModel, where))
    keys = [k.parent() for k in indexes[offset:numresults+1]] # +1 for pagination
    object_list = db.get(keys) # returns a sorted by key_name list of Albums
    

    【讨论】:

      【解决方案2】:

      这里有两个选项:您可以尽可能过滤,然后按照 Alex 的建议在内存中对结果进行排序,或者您可以为相等过滤器而不是不等过滤器重新设计数据结构。

      例如,假设您只想按十年过滤,您可以添加一个字段,对歌曲录制的十年进行编码。要查找十年之前或之后的所有内容,请对您想要跨越的十年进行 IN 查询。这将需要每十年进行一次基础查询,但如果记录数量很大,这仍然比获取所有结果并在内存中排序要便宜。

      【讨论】:

      • 这(重新设计均衡过滤器)实际上是 Brett 在他的 GoogleIO 演讲中所建议的:code.google.com/events/io/sessions/…。我建议观看它 - 非常有见地。
      • 当时我在场,所以不用看。 ;)
      【解决方案3】:

      正如您所说,您不能在一个字段上设置不等式条件,而在另一个字段上设置顺序(或两个字段上的不等式等)。解决方法是简单地使用“最佳”不等式条件来获取内存中的数据(其中“最佳”意味着预期会产生最少数据的那个),然后进一步细化它并在应用程序中通过 Python 代码对其进行排序。

      Python 的列表推导(以及其他形式的循环 &c)、列表的 sort 方法和 sorted 内置函数、标准库中的 itertools 模块等等,都对我们有很大帮助这些类型的任务在 Python 本身中执行起来非常简单。

      【讨论】:

      • 感谢您的回复。我的印象是,我应该尽一切努力避免计算,以避免耗尽 GAE 资源。另一方面,对几百个(最多 1000 个)项目进行排序并不是一项艰巨的任务。返回结果时,您是否在应用程序引擎上完成了这些类型的操作?是否强调资源限制?
      • 我已经完成了,距离 30 秒的最后期限还很远。在我的笔记本电脑上,对随机打乱的 1000 项列表进行排序大约需要 500 微秒,我怀疑 GAE 的服务器比我的笔记本电脑快;-)
      • @Alex:不过,您忽略了获取和解码 1000 个实体的成本,这很重要。
      • @Nick,当然可以,但是如果您获取它们已经排序,则不会降低获取和解码它们的成本!关键是,在内存中排序的成本绝对可以忽略不计。
      • @Alex:但是,如果他只想要前 20 个结果,并且必须获取并排序 1000 个才能获得它们,那么您必须在基准测试中包含很多额外的开销。
      猜你喜欢
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-27
      • 2012-06-13
      • 1970-01-01
      • 2013-06-20
      • 1970-01-01
      相关资源
      最近更新 更多