2009-09-08 6 views
8

約1,000,000人のユーザーがいるとします。特定のユーザーがどのようなポジションにいるのか、どのユーザーが自分の周りにいるのかを知りたい。ユーザーはいつでも新しい成果を得ることができ、彼の立場の更新を見ることができればすばらしいことになります。Django:リーダーボードの作成方法

正直言って、私がこれをやっていると思うあらゆる方法は、時間やメモリの面倒な高価になるでしょう。アイデア?私の最近の考えは、ユーザーをオフラインにしてパーセンタイルバケットを作成することですが、ユーザーに彼の正確な位置を示すことはできません。それはあなたが人々を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) 

答えて

4

私は逆襲ランク付けになるために最小しきい値を満たすためにユーザーに要求することによって、これを解決だと思う - あなただけ正確に上位10%または何をソートする必要があります。

すべての人物を並べ替える場合は、完全に並べ替える必要はありません。2人の有効数字に並べ替えます。 1Mユーザーの場合、トップ100ユーザーのリーダーボードをリアルタイムで更新することができます。次に1000人のユーザーを10人に近づけてから、1人または10パーセントの人数に更新します。あなたは1ラウンドで500,000位から99位にジャンプしません。

指数分布のため、大衆の順序付けはラウンドからラウンドまで信じられないほどびびります。

編集:SO leaderboardをご覧ください。今度は2500から約page 500になります(約20パーセンタイル)。 rep '157との人々に彼らのどちらかの側の10人がrep' 157 'を持っていることを伝えることには何かポイントがありますか?あなたの担当者が一歩上がったり下がったりする場合は、いずれにしても20箇所ジャンプします。もっと極端なのは、現在、1056ページ(2538のうち)の下位ページ、すなわちユーザーの42%が、1と繋がっているということです。もう1ポイントを得て、1055 pagesにジャンプしました。これは、ランクの約37,000増加です。 「もう1点が得られれば37万人を倒すことができる」と言うのはクールかもしれません。 37kの数字の有効数字はいくつですか?

あなたが既にトップにいるまでは、はしごに仲間を知ることに価値はありません。なぜなら、トップ以外のどこにも圧倒的な数があるからです。

+0

誰かがこれをもっと明確にするために編集してください、私は就寝します。 –

+0

私は、ユーザーに彼らの上に人をぶつけて見せることによって目標を与えようとしていましたが、到達できないほど遠くはありませんでした。 –

+0

ディストリビューションの底に向かってのジッタは非常に大きいので、1ポイント上がったり下がったりしても、1Mから数千の場所を得ることができます。スコア分布がどのように見えるかを測定する必要があります。 –

0

100万人ほどではありませんが、私はそれをまず簡単に試していきます。 pointsプロパティがソートしているものであれば、それはデータベース列である必要があります。それから、ランクを得るためには、問題の人よりも大きなポイントを数えるだけです。問題の人の近くにいる他の人を取得するには、より高いポイントと昇順の人のクエリを行い、それをあなたが望む人の数に制限します。

難しいのは、保存時にポイントを計算することです。現在の時間をボーナス乗数として使用する必要があります。 1つのポイントは、今から5日後に1ポイント未満になる必要があります。ユーザーがポイントを獲得することが多い場合は、負荷を処理するキューを作成する必要があります。

関連する問題