代码之家  ›  专栏  ›  技术社区  ›  B.E.

谷歌应用引擎排序问题

  •  1
  • B.E.  · 技术社区  · 16 年前

    我正在使用以下类存储一些数据:

    class NewsArticle(db.Model):
        score = db.FloatProperty(default=0.0)
        date_scored = db.DateTimeProperty()
        ...
    

    我需要做的是在某个时间范围内获得得分最高的新闻文章实体(例如,获得今天或上周得分最高的数据实体)。

    我尝试了以下方法:

    query = db.GqlQuery('SELECT * FROM NewsArticle WHERE date_created > DATETIME(:year, :month, :day, 0, 0, 0) ORDER BY score DESC', year=date.selected_year, month=date.selected_month, day=date.selected_day)
    

    但这不起作用,因为数据存储要求

    第一个排序属性必须是 与不等式滤波性质相同

    我考虑在特定时间段内获取所有新闻文章实体,然后在我的应用程序中进行分数排序,但是我期望得到大量的结果,因此内存中的排序将不高效。

    对于我的问题还有什么其他的解决办法?

    4 回复  |  直到 16 年前
        1
  •  5
  •   jbochi    16 年前

    你可以:

    1. 仅按时间框架筛选并按内存中的分数排序,或者,

    2. 如果可以将时间范围限制为整天和整周,请在模型中包含其他属性,以将周保存为整数,将日保存为 DateProperty 做一个简单的等式检查。

    编辑:要了解更多信息,请查看 Restrictions on Queries

        2
  •  1
  •   Alex Martelli    16 年前

    我在等一个很大的数字 结果,因此内存排序不会 提高效率。

    您最多可以从一个查询中获得1000个结果,因此按每种方式对它们进行排序 极其 高效——例如,考虑一下,在我的MacBookAir上(第一天,最慢的机型):

    $ python -mtimeit -s'import random; x=range(1000); random.shuffle(x)' 'y=sorted(x)'
    1000 loops, best of 3: 714 usec per loop
    

    Appengine的CPU基本上比空气快,所以对1000个结果进行排序的700微秒将是 非常 悲观的估计;这与 几十毫秒 对于 取来 数据——所以,别担心 完全 关于排序:只要你能得到你想要的结果,你就会没事的。

    顺便说一句,要评估任务中可能的应用程序引擎性能,请参见Guido van Rossum的演示。 here --他声称10-50毫秒 db.get() (50-100) put 等等)。

    如果您期望一个查询的结果超过1000个,这通常意味着您需要取消表的规格化,以将查询的结果减少到1000个以下。例如,在您的案例中,假设您期望每天大约有500-700个条目——在这种情况下,获得今天的所有结果是没有问题的,但是一周 当然是个问题:您需要将查询减少到“正常”查询量的20%或更少。

    例如,假设你的分数在0-100之间,大约是均匀分布的。在这种情况下,您可以向实体添加一个布尔字段“topcandidate”:保存实体时,如果分数在85-100范围内,则将该字段设置为“真”(如您所见,这意味着表将不规范化,因为该字段表示逻辑上的冗余信息)。

    当您获取每周的顶级结果时,您添加相等条件以使TopCandidate为真。而不是3500-4900个结果,这应该会让你降到500-900——最高得分15%左右,之后你可以在内存中对它们进行排序,然后选择,比如说,前100个。

    当然,确切的数字取决于 score 字段(更可能是钟形曲线,而不是平面均匀分布)以及您需要多少“高分候选人”,但这是一个通常有用的方法,可以在1000个结果限制范围内工作。

        3
  •  0
  •   Sri    16 年前

    试试这个:

    import datetime
    ...
    query = Data.gql('SELECT * FROM NewsArticle WHERE date_created >= :today ORDER BY score DESC', today=datetime.date.today())
    
        4
  •  -1
  •   z33m    16 年前

    我认为按多个属性排序可能有效。只需使用第一个不等式属性作为第一个排序属性。

    query = db.GqlQuery('SELECT * FROM NewsArticle WHERE date_created > DATETIME(:year, :month, :day, 0, 0, 0) ORDER BY date_created, score DESC', year=date.selected_year, month=date.selected_month, day=date.selected_day)