8

約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)
4

2 に答える 2

4

Counterstrikeは、ユーザーがランク付けされるための最小しきい値を満たすことを要求することでこれを解決すると思います。上位10%などを正確に並べ替えるだけで済みます。

全員を並べ替える場合は、完全に並べ替える必要はないことを考慮してください。有効数字2桁に並べ替えます。100万人のユーザーがいる場合、上位100人のユーザーのリーダーボードをリアルタイムで更新できます。次の1000人のユーザーは10人に最も近く、大衆は1%または10%に最も近くなります。1ラウンドで500,000位から99位にジャンプすることはありません。

500,000の場所の上下に10のユーザーコンテキストを取得することは無意味です。指数分布のため、大衆の順序はラウンドごとに非常に不安定になります。

編集:SOリーダーボードを見てください。次に、2500ページのうち500ページ(約20パーセンタイル)に移動します。担当者「157」の人に、両側の10人にも担当者「157」があることを伝える意味はありますか?担当者がポイントを上げたり下げたりすると、どちらの方法でも20か所ジャンプします。さらに極端なのは、現在、下位1056ページ(2538のうち)、つまりユーザーの下位42%が担当者1と結びついていることです。もう1つのポイントを獲得し、1055ページにジャンプしました。これはランクがおよそ37,000増加します。「もう1ポイント稼げば3万7千人を倒せる!」と言うのもいいかもしれません。しかし、37kの数字がいくつの有効数字を持っているかは重要ですか?

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

于 2009-09-08T02:07:59.330 に答える
0

100万はそれほど多くないので、最初は簡単な方法で試してみます。pointsプロパティがソート対象である場合、それはデータベース列である必要があります。次に、問題の人物よりも多くのポイントをカウントして、ランクを取得できます。問題の人の近くに他の人を近づけるには、ポイントの高い人にクエリを実行し、昇順で並べ替えて、必要な人の数に制限します。

トリッキーなことは、保存時にポイントを計算することです。現在の時刻をボーナス乗数として使用する必要があります。1ポイントは、5日後に1ポイント未満の数値に変換する必要があります。ユーザーが頻繁にポイントを獲得する場合は、負荷を処理するためのキューを作成する必要があります。

于 2009-09-08T19:14:35.167 に答える