Django:如何创建排行榜

时间:2009-09-08 01:58:50

标签: python sql django leaderboard

假设我有大约1,000,000名用户。我想找出任何给定用户所处的位置,以及他周围的用户。用户可以随时获得新的成就,如果他能看到他的常规更新,那就太棒了。

老实说,我想到这样做的每一种方式都会在时间和/或记忆上花费巨大。想法?到目前为止,我最接近的想法是让用户离线并构建百分位桶,但这无法向用户显示他的确切位置。

一些代码,如果这可以帮助你django人:

class Alias(models.Model) :
    awards = models.ManyToManyField('Award', through='Achiever')

    @property
    def points(self) :
        p = cache.get('alias_points_' + str(self.id))
        if p is not None : return p

        points = 0
        for a in self.achiever_set.all() :
            points += a.award.points * a.count

        cache.set('alias_points_' + str(self.id), points, 60 * 60) # 1 hour
        return points

class Award(MyBaseModel):
    owner_points = models.IntegerField(help_text="A non-normalized point value. Very subjective but try to be consistent. Should be proporional. 2x points = 2x effort (or skill)")
    true_points = models.FloatField(help_text="The true value of this award. Recalculated with a cron job. Based on number of people who won it", editable=False, null=True)

    @property
    def points(self) :
        if self.true_points :
            # blend true_points into real points over 30 days
            age = datetime.now() - self.created
            blend_days = 30
            if age > timedelta(days=blend_days) :
                age = timedelta(days=blend_days)
            num_days = 1.0 * age.days / blend_days
            r = self.true_points * num_days + self.owner_points * (1 - num_days)
            return int(r * 10) / 10.0

        else :
            return self.owner_points


class Achiever(MyBaseModel):
    award = models.ForeignKey(Award)
    alias = models.ForeignKey(Alias)
    count = models.IntegerField(default=1)

2 个答案:

答案 0 :(得分:4)

我认为反击通过要求用户达到排名的最低门槛来解决这个问题 - 你只需要准确排序前10%或其他什么。

如果您想对每个人进行排序,请考虑您不需要对它们进行完美排序:将它们排序为2位有效数字。使用1M用户,您可以实时更新前100名用户的排行榜,接下来的1000名用户到最近的10名,然后质量到最接近的1%或10%。你不会在一轮中从500,000跳到99。

将10个用户上下文置于500,000以上是毫无意义的 - 由于指数分布,群众的顺序将会令人难以置信地紧张不安。

编辑:看看SO leaderboard。现在转到2500中的page 500(大约20%)。是否有任何意义告诉代表'157'的人,他们两边的10个人也有'157'代表?如果你的代表上升或下降一点,你将以任何一种方式跳20个位置。更极端的是,现在最底层的1056页(2538个),或者最低42%的用户,与rep 1相关联。你得到一个点,然后你跳了1055 pages。排名大约增加37,000。告诉他们“如果再多一点,你可以击败37,000人!”可能会很酷。但37k数字有多少重要数据是否重要?

在你已经处于最顶层之前,了解你的同龄人是没有价值的,因为除了顶部之外的任何地方,都有绝大多数。

答案 1 :(得分:0)

一百万不是那么多,我会先用简单的方法来尝试。如果points属性是您要排序的东西,则需要是数据库列。然后,您可以只计算比相关人员更多的积分来获得排名。为了让其他人靠近有问题的人,您可以查询具有较高积分的人并按升序将其限制为您想要的人数。

棘手的事情是计算保存点数。您需要使用当前时间作为奖励乘数。现在有一点需要变成一个从现在起5天内不到1点的数字。如果您的用户经常获得积分,则需要创建一个队列来处理负载。