2009-09-08 26 views
8

Powiedzmy, że mam około 1 000 000 użytkowników. Chcę się dowiedzieć, na jakim stanowisku znajduje się dany użytkownik i którzy użytkownicy są wokół niego. Użytkownik może uzyskać nowe osiągnięcie w dowolnym momencie, a gdyby mógł zobaczyć swoją stałą aktualizację, byłoby wspaniale.Django: Jak utworzyć tabelę wyników

Szczerze mówiąc, każdy sposób, w jaki to robię, byłby niezwykle kosztowny w czasie i/lub pamięci. Pomysły? Do tej pory moim najbliższym pomysłem jest zamówienie użytkowników offline i budowanie wiader percentyla, ale to nie może pokazać użytkownikowi jego dokładnej pozycji.

Niektóre kodu, jeśli pomaga Ci django osoby:

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) 

Odpowiedz

4

myślę Counterstrike rozwiązuje ten problem, wymagając od użytkowników, aby spełnić minimalny próg, by stać się w rankingu - trzeba tylko dokładnie posortować Top 10% lub cokolwiek .

Jeśli chcesz posortować wszystkich, rozważ, że nie musisz ich perfekcyjnie sortować: posortuj je do 2 cyfr znaczących. Dzięki 1M użytkownikom możesz zaktualizować tabelę wyników dla 100 najlepszych użytkowników w czasie rzeczywistym, kolejnych 1000 użytkowników do najbliższych 10, a następnie mas do najbliższego 1% lub 10%. Nie wyskoczysz z miejsca 500 000 na miejsce 99 w jednej rundzie.

Bez znaczenia dla uzyskania kontekstu 10 użytkowników powyżej i poniżej miejsca 500 000 - uporządkowanie mas będzie niewiarygodnie roztrzęsione od rundy do rundy ze względu na rozkład wykładniczy.

Edytuj: Spójrz na SO leaderboard. Teraz przejdź do page 500 z 2500 (około 20 percentyla). Czy jest jakaś kwestia mówienia ludziom z przedstawicielem '157', że 10 osób po obu stronach ma również rep '157'? Przeskoczysz o 20 miejsc w każdy sposób, jeśli twój reprezentant pójdzie w górę lub w dół. Bardziej ekstremalne jest to, że obecnie 1056 stron na dole (na 2538) lub na dole 42% użytkowników jest powiązanych z numerem 1. Dostajesz jeszcze jeden punkt, a Ty podskoczyłeś 1055 pages. Co stanowi wzrost o 37 000 w rankingu. To może być fajne powiedzieć im "możesz pokonać 37 000 ludzi, jeśli zdobędziesz jeszcze jeden punkt!" ale czy ma znaczenie, ile znaczących liczb ma liczba 37 tys.

Nie ma żadnej wartości w poznawaniu rówieśników na drabinie, dopóki nie jesteś już na szczycie, bo gdziekolwiek, ale na samym szczycie, jest ich przytłaczająca liczba.

+0

Ktoś proszę edytować to, aby być bardziej elokwentnym, idę do łóżka. –

+0

Próbowałem dać użytkownikom cel, pokazując im ludzi powyżej nich, aby pokonać, ale nie za daleko, aby być nieosiągalnym. –

+0

Jitter w kierunku dolnej części dystrybucji będzie tak wielki, że nawet wznoszenie się lub opuszczanie o 1 punkt spowoduje spadek lub zdobycie kilku tysięcy miejsc na 1M. powinieneś zmierzyć, jak wygląda twoja ocena wyniku. –

0

Milion to nie tyle, ale najpierw wypróbuję to w prosty sposób. Jeśli właściwość points jest rzeczą, którą sortujesz, musi to być kolumna bazy danych. Następnie możesz po prostu zrobić liczbę punktów większą od danej osoby, aby uzyskać rangę. Aby przyciągnąć inne osoby w pobliżu danej osoby, wykonuj zapytanie osób o wyższych punktach i sortuj rosnąco, ograniczając liczbę osób, które chcesz.

Podstępem będzie obliczenie punktów przy zapisie. Musisz użyć bieżącego czasu jako mnożnika bonusowego. Jeden punkt teraz musi zmienić się w liczbę, która jest mniejsza niż 1 punkt 5 dni od teraz. Jeśli Twoi użytkownicy często zdobywają punkty, musisz utworzyć kolejkę do obsługi obciążenia.

Powiązane problemy