2009-09-08 3 views
8

Sagen wir, ich habe etwa 1.000.000 Benutzer. Ich möchte herausfinden, in welcher Position sich ein bestimmter Benutzer befindet und welche Benutzer sich um ihn herum befinden. Ein Benutzer kann jederzeit einen neuen Erfolg erzielen, und wenn er sein stehendes Update sehen könnte, wäre das wunderbar.Django: Wie man eine Bestenliste erstellt

Ehrlich gesagt, jede Art, die ich denke, dies zu tun wäre schrecklich teuer in Zeit und/oder Speicher. Ideen? Meine bisher beste Idee ist es, die Benutzer offline zu ordern und Perzentil-Buckets zu erstellen, aber das kann einem Benutzer nicht seine genaue Position zeigen.

Einige Code, wenn Sie, dass Menschen django hilft:

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) 

Antwort

4

Ich denke, dies löst Counter von Nutzern erfordern eine Mindestschwelle zu erfüllen gewählt werden - man muss nur genau die Top 10% sortieren oder was auch immer .

Wenn Sie alle sortieren möchten, beachten Sie, dass Sie sie nicht perfekt sortieren müssen: Sortieren Sie sie in zwei signifikante Zahlen. Mit 1M Benutzern können Sie die Rangliste für die Top 100 Benutzer in Echtzeit aktualisieren, die nächsten 1000 Benutzer auf die nächsten 10, dann die Massen auf die nächsten 1% oder 10%. Sie werden in einer Runde nicht von Platz 500.000 auf Platz 99 springen.

Es ist sinnlos, den 10 Benutzer Kontext über und unter 500.000 zu bekommen - die Reihenfolge der Massen wird aufgrund der exponentiellen Verteilung von Runde zu Runde unglaublich nervös.

Bearbeiten: Werfen Sie einen Blick auf die SO leaderboard. Gehen Sie jetzt zu page 500 von 2500 (ungefähr 20. Perzentil). Ist es sinnvoll, den Leuten mit der Bemerkung zu sagen, dass die 10 Leute auf beiden Seiten von ihnen auch die '157' haben? Du wirst 20 Plätze auf jede Art springen, wenn dein Repräsentant einen Punkt nach oben oder unten geht. Extremer ist, dass jetzt die unteren 1056 Seiten (von 2538), oder die unteren 42% der Benutzer, mit rep 1. verbunden sind. Sie bekommen einen weiteren Punkt, und Sie sind auf 1055 pages gesprungen. Das ist ungefähr eine 37.000 Steigerung im Rang. Es könnte cool sein ihnen zu sagen "Du kannst 37k Leute schlagen, wenn du noch einen Punkt bekommst!" Aber ist es wichtig, wie viele signifikante Zahlen die 37k-Zahl hat?

Es macht keinen Sinn, Ihre Kollegen auf einer Leiter zu kennen, bis Sie bereits an der Spitze sind, denn überall außer der Spitze gibt es eine überwältigende Anzahl von ihnen.

+0

jemand bitte bearbeiten Sie dies, um mehr artikulieren, ich gehe ins Bett. –

+0

Ich habe versucht, den Benutzern ein Ziel zu geben, indem ich ihnen die Leute über ihnen zeigen wollte, aber nicht zu weit, um unerreichbar zu sein. –

+0

der Jitter in Richtung der Unterseite der Verteilung wird so groß sein, dass sogar auf oder ab gehen 1 Punkt Sie fallen lassen oder gewinnen Sie mehrere tausend Plätze aus 1M. Sie sollten messen, wie Ihre Score-Verteilung aussieht. –

0

Eine Million ist nicht so viel, ich würde es zuerst einfach versuchen. Wenn die Eigenschaft points das Objekt ist, nach dem Sie sortieren, muss es sich um eine Datenbankspalte handeln. Dann kannst du einfach mehr Punkte zählen als die betreffende Person, um den Rang zu erhalten. Um andere Personen in die Nähe einer Person zu bringen, führen Sie eine Abfrage von Personen mit höheren Punkten durch und sortieren aufsteigend nach der Anzahl der gewünschten Personen.

Das schwierige Ding wird die Punkte beim Speichern berechnen. Sie müssen die aktuelle Zeit als Bonusmultiplikator verwenden. Ein Punkt muss nun in eine Zahl umgewandelt werden, die weniger als 1 Punkt in 5 Tagen beträgt. Wenn Ihre Benutzer häufig Punkte sammeln, müssen Sie eine Warteschlange erstellen, um die Belastung zu bewältigen.