Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] Ranking użytkowników
Forum PHP.pl > Forum > PHP
devbazy
Witam,

przejdę od razu do meritum. Otóż planuję napisać skrypt (jak w tytule wątku) i zastanawiam się nad pewną kwestią. Załóżmy, że algorytm obliczałby ilość zdobytych plusów za komentarze, posty napisane przez użytkownika oraz jego aktywność (podobne działanie jak na portalu wykop.pl) i według tego ustalałby jego pozycję w rankingu (nie mam zamiaru robić tego dynamicznie, czyli po każdej aktywności odpalać odpowiedni skrypt - wręcz przeciwnie, posłużę się CRON'em, bo myślę, że to najlepsza rozwiązanie, chociaż jestem otwarty na wszelkie sugestie). Na samym początku, po rejestracji na witrynie użytkownik miałby status - poza rankingiem (o ile na stronie byłoby zarejestrowanych więcej niż 300 użytkowników, dajmy na to, że limit to właśnie te 300 miejsc), a dopiero z czasem (w miarę jego aktywności) mógłby zdobyć jakąś sensowną pozycję. Będę wdzięczny za jakiekolwiek propozycje, począwszy od wstępnego projektu struktury tabel, aż po sugestie dot. rozwiązania tego dość irytującego problemu.

Z góry dziękuje za wszelaką pomoc.
tehaha
ale masz jakiś konkretny problem? skoro już dokładnie wiesz co chcesz osiągnąć to pozostaje już tylko usiąść i to zrobić, cron to całkiem dobra opcja do tego, żeby wyliczać to w nocy i pobierać potem ranking z prostej tabeli, ponadto warto by też uwzględnić daty, tzn może lepiej żeby algorytm liczył tylko aktywność z ostatniego miesiąca, żeby byli to obecnie aktywni użytkownicy a nie np. Ci którzy kiedyś dużo korzystali i już przestali, chociaż to już kwestia indywidualna i wybór należy do Ciebie
PiotrekM
normalna tabela z użytkownikami

zapytaniem zliczasz posty, tematy etc.

tworzysz sobie tablice wg. takiego schematu
Kod
$rate = array(
'post' => 5,
'thread' => 15,
);

wymnażasz.
w zapytaniu dajesz limit do 300 i wyświetlasz userów w rankingu.
cronem aktualizujesz raz na 24 godziny.

zawsze możesz dać klauzue where i sprawdzać czy użytkownik jest w serwisie przynajmniej tydzień, czy ile tam chcesz smile.gif
devbazy
@tehaha: oczywiście, będę brał pod uwagę jedynie aktywność z określonego przedziału czasu - ostatni miesiąc wydaje się być sensownym okresem.

Już wyjaśniam jak zamierzam to zrobić i nad czym się zastanawiam (chociaż temat powstał również w tym celu, by podłapać najbardziej optymalne rozwiązanie smile.gif). Po tym jak algorytm wykona wszystkie potrzebne obliczenia i posortuje wyniki od największego - będzie ustalana pozycja. Użytkownik z najwyższym wynikiem będzie miał pierwszą pozycję w rankingu, kolejny - drugą itd. Oczywiście, skrypt będzie obliczał pozycję wyłącznie 300 najlepszych użytkowników (o ile jest więcej użytkowników i jeżeli jest ustalony taki limit). Załóżmy, że tą pozycję będę zapisywał w polu rank_pos (int) - tabela users.

Jedyne rozwiązanie jakie nasuwa mi się obecnie na myśl (ciężko się człowiekowi myśli, gdy z roboty przychodzi wkurw**** - wiem, słaba wymówka), to skonstruowanie odpowiedniego zapytania, a następnie wyciągnięcie 300 wyników pętlą - podczas działania skryptu - po każdym wyniku skrypt wykonywałby kolejne zapytanie (UPDATE) - ustalenie pozycji w polu rank_pos według tego co zostało wyświetlone wcześniej. Łącznie skrypt będzie musiał wykonać 600 zapytań do bazy i zastanawiam się czy nie da się zrobić tego prościej, bardziej optymalnie.

Mam nadzieję, że nie opisałem tego zbyt chaotycznie.
tehaha
1. słaba wymówka co myślisz, że my nie pracujemy?
2. czas z jakiego będziesz wyliczał ranking jest uzależniony od typu serwisu i ilość użytkowników, dla dużego serwisu to nawet ranking z tygodnia ma sens.
3. Po co jakiś UPDATE? Robisz sobie oddzielną tabelę na ten ranking gdzie będziesz trzymał tylko ID użytkownika i jego punkty jeżeli chcesz wyświetlasz

Czyli jak będziesz sobie cronem liczył ranking to sumujesz wszystkie posty, komentarze czy cokolwiek tam chcesz uwzględniać w tym algorytmie, wyliczasz dla wszystkich, usuwasz rekordy z tej tabeli z rankingiem i jednym zapytaniem wstawiasz rekordy z kolejnością użytkowników i całość załatwisz przy pomocy kilku zapytań
devbazy
1) Wcale nie twierdzę, że są tu sami bezrobotni smile.gif
2) Na początku myślę, że wystarczy odpalić algorytm co dwa dni. Później stopniowo (w zależności ilości użytkowników i ich aktywności) ten czas można wydłużać.
3) Pasuje te dane gdzieś zapisać, stąd pomysł z aktualizacją pozycji użytkownika modyfikując pole rank_pos.

Dane (takie jak punkty, id użytkownika) rzecz jasna będą przechowywane w innej tabeli, która będzie miała następującą strukturę:

- id (int)(auto increment)
- user_id (int)
- comment_points (int)
- post_points (int)

We wspomnianym wcześniej przeze mnie rozwiązaniu można byłoby to załatwić za pomocą dwóch zapytań (x300 - przez taką ilość użytkowników przechodziłaby pętla) - pobranie danych i aktualizacja pozycji w rankingu.
tehaha
co do punktu 3 to chodziło mi "po co robić 300 razy UPDATE w pętli jak można zrobić jeden raz INSERT", zapytania w pętli to najgorsze możliwe rozwiązanie być może w Twoim przypadku nie zrobi to różnicy bo skoro będzie to cron obsługiwał to nie będzie problemu ale lepiej uczyć się stosować prawidłowe rozwiązania, skoro chodzi tylko o zliczanie postów i komentarzy a potem wpisanie tego do innej tabeli to całość możesz załatwić przy pomocy 4 zapytań:
1. pobierasz liczbę postów dla użytkowników przy pomocy COUNT() i GROUP BY user_id
2. pobierasz liczbę komentarzy dla użytkowników przy pomocy COUNT() i GROUP BY user_id
3. usuwasz rekordy z tabeli ranking
4. wstawiasz rekordy do tabli ranking
devbazy
Mówisz, że można to wszystko zrobić za pomocą 4 zapytań bez stosowania jakiejkolwiek pętli? Nie wiem czy do końca zrozumiałem o co chodzi, byłbym wdzięczny za ukazanie tego na jakimś prostym przykładzie. W moim przypadku wyglądałoby to tak (zdaje sobie sprawę, że można to zrobić prościej i lepiej, dlatego też postanowiłem tutaj napisać):

  1. $query = mysql_query("SELECT user_id FROM some_table ORDER BY comment_points DESC, post_points DESC LIMIT 300"); //zakładając, że jest więcej userów w bazie
  2.  
  3. $i = 1;
  4. while($row = mysql_fetch_array($query))
  5. {
  6. mysql_query("UPDATE users_table SET rank_pos='".$i."' WHERE id='".$row['user_id']."' ");
  7. $i++;
  8. }
  9.  


^ zobrazowałem to, o czym wcześniej mówiłem.

Łącznie by wyszło 600 zapytań. Może dla niektórych to nie wiele biorąc pod uwagę fakt, że byłoby to wykonywane CRON'em raz na jakiś czas. Ale po co niepotrzebnie obciążać bazę, skoro jest zapewne skuteczniejszy sposób?
tehaha
dokładnie Ci nie napiszę bo nie wiem jakie masz tabele i w jaki sposób chcesz wyliczać te punkty, więc napiszę Ci tylko kod zastępczy do tej pętli

po co Ci ten ranking w tabeli users, wszystko będzie prostsze jak dasz to do oddzielnej, np:

tabela user_rank
rank_id int11
user_id int11
points int11

  1. $query = mysql_query("SELECT user_id FROM some_table ORDER BY comment_points DESC, post_points DESC LIMIT 300"); //zakładając, że jest więcej userów w bazie
  2.  
  3. $i = 1;
  4. $query_parts = array();
  5. while($row = mysql_fetch_array($query))
  6. {
  7. $sum_points = $row['comment_points']+$row['post_points'];
  8. $query_part[]= "({$row['user_id']}, {$sum_points})";
  9. }
  10. $query = implode(', ', $query_parts);
  11.  
  12. $query = mysql_query("DELETE FROM table_ranking");
  13. $query = mysql_query("INSERT INTO table_ranking(user_id, points) VALUES".$query);


oczywiście to nie jest gotowy kod, tylko taki , żeby Ci pokazać o co chodzi

p.s. nie wiem czy zdajesz sobie sprawę ale ustawienie ORDER po obu kolumnach oznacza, że najpierw będzie sortowanie względem comment_points a dopiero tam gdzie wartości comment_points są takie same następuje sortowanie po post_points, więc uzyskasz zafałszowany wynik bo ktoś kto ma np. 0 punktów za komentarze a 5 milionów za posty to i tak wyląduje na końcu listy

lepszym rozwiązaniem będzie zsumowanie tego czyli coś takiego:
  1. SELECT user_id, SUM(comment_points+post_points) AS sum_points FROM some_table GROUP BY user_id ORDER BY sum_points DESC LIMIT 300
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.