Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Forum - mechanizm oznaczania tematow jako przeczytane
Forum PHP.pl > Forum > PHP
ElemenT
Witam,

Jestem na etapie konczenia pisania forum jednak zostalo mi pare dupereli do dopisania m.in. oznaczanie czy ktos przeczytal dany temat czy nie.

Wymyslilem taki algorytm :

1. sprawdzam date ostatniego logowania lub wejscia (w zaleznosci czy jestem zalogowany czy nie)
2. wstepnie zaznaczam tematy jako nieprzeczytane od tamtego czasu
3. tematy obejrzane zaznaczam jako przeczytane (np zapisujac do cookiesa co widzialem, moze ew z jakas data)

Ma ktos jakies propozycje jak taki algorytm rozwinac ?
Kicok
Przy każdej odsłonie strony dla zalogowanego użytkownika.

1. Pobieramy z bazy datę ostatniej aktywności użytkownika
2. Nadpisujemy datę w bazie danych obecną datą
3. Wszystkie posty napisane po ostatniej akcji użytkownika dodajemy do tabeli z nieprzeczytanymi postami (struktura poniżej)
4. Jeśli użytkownik wyświetla właśnie jakieś posty, to usuwasz je z tabeli z nieprzeczytanymi postami

A struktura tej tabeli to po prostu:
Kod
+---------+---------+
| user_ID | post_ID |
+---------+---------+
|    2    |    32   |
|    2    |   245   |
|   14    |    32   |
|   15    |  1244   |



Tabela ta może się trochę rozrosnąć, więc można zastosować jakieś limity, typu "max 300 zapisanych postów nieprzeczytanych dla jednego użytkownika, jeśli jest ich więcej to najstarsze będą oznaczone jako przeczytane"
ElemenT
tylko w moim przypadku to troche zly pomysl tongue.gif
tablica sie zrobi gigantyczna bo
1. obecnie mam kolo 17 tys kont
2. liczba tematow 10 tys
3. liczba zakladanych tematow dziennie srednio 50

i przy takich liczbach taka tablica moze byc duza i moze spowalniac forum a zalezy mi by moje nowe
forum smigalo jak smiga obecnie smile.gif

ma ktos inne rozwiazania ?
a moze algorytm ktos zna jaki jest np na IPB lub VBulletin
Kicok
Cytat
1. obecnie mam kolo 17 tys kont


Zauważ, że rekordy do tej tabeli dodawane będą dopiero po zalogowaniu się użytkownika, nie po napisaniu postu. Więc jeśli z tych 17 tys. kont aktywnych użytkowników jest 7 tyś, to tylko oni będą wpływali na zapełnienie tabeli.


Cytat
i przy takich liczbach taka tablica moze byc duza i moze spowalniac forum a zalezy mi by moje nowe
forum smigalo jak smiga obecnie


Dodanie jednego miliona rekordów do tabeli:
  1. <?php
  2.  
  3. error_reporting( E_ALL | E_STRICT );
  4.  
  5.  
  6. $conn_id = mysql_connect( 'localhost', 'root', 'root' );
  7. mysql_select_db( 'test', $conn_id );
  8.  
  9.  
  10. for( $i=0; $i<1000000; $i++ )
  11. {
  12. $user_id = mt_rand( 1, 1000 );
  13. $post_id = mt_rand( 1, 50000 );
  14.  
  15. mysql_unbuffered_query( "INSERT INTO unread (user_id, post_id) VALUES ({$user_id}, {$post_id})", $conn_id );
  16. }
  17.  
  18. mysql_close( $conn_id );
  19.  
  20. ?>



Proste testy wydajnościowe:
  1. <?php
  2.  
  3. error_reporting( E_ALL | E_STRICT );
  4.  
  5.  
  6. $conn_id = mysql_connect( 'localhost', 'root', 'root' );
  7. mysql_select_db( 'test', $conn_id );
  8.  
  9.  
  10. $user_id = mt_rand( 1, 1000 );
  11.  
  12. $start = microtime( true );
  13. $result = mysql_query( "SELECT post_id FROM unread WHERE user_id = {$user_id}", $conn_id );
  14. $stop = microtime( true );
  15.  
  16.  
  17. $count = mysql_num_rows( $result );
  18. $time = bcsub( $stop, $start, 8 );
  19.  
  20.  
  21. echo "User ID: {$user_id}<br />";
  22. echo "Wykonano w <b>{$time}</b>s.<br />";
  23. echo "Ilość wyników: {$count}";
  24.  
  25.  
  26. mysql_close( $conn_id );
  27.  
  28. ?>



Na moim komputerze wyniki mieściły się w granicach 0.003 - 0.005s. Jeśli dla ciebie to zbyt dużo, to faktycznie, powinieneś poszukać jakiegoś mniej dokładnego, ale szybszego rozwiązania.
Oczywiście jest to test dla prostego zapytania SELECT. W boju trzeba będzie jednak używać czegoś bardziej skomplikowanego, typu:
  1. SELECT u.post_id
  2. FROM unread AS u
  3. JOIN posts AS p ON ( u.post_id = p.post_id )
  4. WHERE ( p.topic_id = $topic_id ) AND ( u.user_id = $user_id )

jednak nie sądzę, żeby w tym przypadku czas wykonania zapytania podskoczył drastycznie. Wszystko zależy od poprawnego założenia indeksów na kolumny (więcej: google -> MySQL optymalizacja)
ElemenT
dobra przekonales mnie, przetestuje takie cos

tylko teraz dalej... co w przypadku gdy user nie jest zalogowany, a takich tez srednio na forach jest duzo, tylko przegladaja tematy bo czegos szukaja a wypowiadac sie im nie chce ani nie chce sie im zakladac kont (dluga procedura aktywacji poprzez email - serwery coraz czesciej maja graylisting co opoznia nawet do 10 min)

moze tam po prostu zastosuje stary algorytm albo go jakos przebuduje
makusik
ElemenT@: ja to w swoim forum rozwiazalem ciasteczkiem,
informacje przechowuje w zmiennej tablicowej potem serialize i unserialize,

dzieki temu dziala nawet jesli uzytkownik nie jest zalogowany i zadnych informacji nie przechowuje w bazie,

jesli interesuja cie szczegoly moge zerknac jak dokladnie to rozwiazalem
UDAT
Cytat(makusik @ 4.08.2007, 13:38:14 ) *
ElemenT@: ja to w swoim forum rozwiazalem ciasteczkiem,
informacje przechowuje w zmiennej tablicowej potem serialize i unserialize,
dzieki temu dziala nawet jesli uzytkownik nie jest zalogowany i zadnych informacji nie przechowuje w bazie,


1. Czyli zaloguje się z innego komputera, innej przeglądarki lub po prostu po usunięciu ciastek, to znowu nie będę miał przeczytanych tematów.

2. Teraz trochę rachunków
50 tematów/dziennie * 365dni * 15bajtów/temat = 273 750 b = 273 kB wysyłanych danych przy każdym wywołaniu - to trochę dużo? Przy moim uploadzie zajmie to conajmniej 30s.

3. A co zrobisz gdy do tematu zostanie dodany nowy post? Może zapisujesz przeczytane posty.? Załóżmy że temat ma 8-10 postów to daje po roku jakieś 1.6-2.7Mb danych.


Lepsza jest baza danych.
ElemenT
limit ciastka ma 4 KB
wiec tyle danych nie przeniesiesz

mysle ze trzeba by skorzystac z sesji i tam zapisac dane, przechowaja sie w /tmp i nie trzeba bedzie ich sciagac
wiec tylko PHPSESSID bedzie pobieralo, wynajdywalo po tym dane o czytanych tematach i po klopocie

tak mi sie przynajmniej wydaje ze moze to byc dobre rozwiazanie biggrin.gif

UDAT@ : AD 3 - jezeli dochodzi nowy post to data tematu jest wyzsza niz data ostatniego logowania (data startowa) i automatem zaznacza jako nieprzeczytany
dopiero jak wejdziesz to zapiszesz dane ze temat odwiedziles

poza tym wg mnie lepiej przechowywac info o przeczytanych tematach niz o nie przeczytanych
przyklad

mam 50 tematow dziennie podzielonych na 15 tablic, usera interesuje tylko jedna tematyka wiec odwiedza te zaluzmy 10 tematow dziennie i robimy wpisy na 10 tematow a nie na 40 pozostalych

dobra zrobilem w wygladzie tematow
teraz zagwostka przy wygladzie indexu

gdzie mamy ikonke jedna dla forum
i scenariusz taki :

wchodze : widze ze swieci sie czerwona ikonka czyli sa nowe tematy
wchodze do srodka a tam 20 tematow

wchodze do kazdego
wszystkie odznaczam

i teraz by na indexie forum zmienila mi sie ikonka na zielona (oznaczenie ze nie ma nowych tematow)

ma ktos jakis pomysl ?

moze zrobic jakis tablicowy marker ktory podczas budowania listy tematow bedzie sprawdzal co juz przeczytalem a czego nie
tylko co w przypadku jak bede mial wiecej tematow nieprzeczytanych i bedzie podzial na 2 strony ?
i np na 1 wszystkie przeczytam, zostanie 2, marker by musial wiedziec ile jest na kolejnych stronach :/

ciezki temat
Kicok
- Gość wyświetla stronę
--- Sprawdzamy czy sesja dla tego użytkownika została utworzona
----- Jeśli nie, to sprawdzamy, czy zostało wysłane ciasteczko z datą "ostatniej akcji" użytkownika
------- Jeśli nie: zapisujemy obecną datę do sesji (jako "ostatnia wizyta")
------- Jeśli tak: zapisz datę "ostatniej akcji" z ciasteczka do sesji jako "ostatnia wizyta"
----- Zapisujemy do sesji drugą datę, aktualną (jako "ostatnia akcja")
----- Oznaczamy wszystkie posty napisane między "ostatnia wizyta" a "ostatnia akcja" jako nieprzeczytane
----- Wysyłamy ciasteczko z "ostatnią akcją" użytkownika
--- Jeśli sesja została już wcześniej utworzona, to:
----- Aktualizujemy datę "ostatniej akcji" ("ostatnią wizytę" zostawiamy w spokoju)
----- Oznaczamy wszystkie postu napisane między "ostatnia wizyta" a "ostatnia akcja" jako nieprzeczytane *
----- Wysyłamy ciasteczko z obecną datą jako "ostatnia akcja"


* Dodatkowo, żeby podczas przeglądania strony w ramach jednej sesji gościowi nie wyświetlały się dopiero co przeczytane posty jako nieprzeczytane, trzeba będzie dodawać ich (przeczytanych w ramach tej sesji postów) ID do sesji i w miejscu oznaczonym gwiazdką wyłączać te posty z listy nieprzeczytanych.

Jedyny mankament tego rozwiązania:
- Gość wchodzi na strone
- Ma 5 postów nieprzeczytanych
- Czyta 3 z nich
- Wyłącza przeglądarkę
- Wchodzi na stronę ponownie
- Nie widzi już tych 2 postów jako nieprzeczytane
Ale jeśli gościom będzie takie zachowanie forum przeszkadzało, to zawsze się mogą zarejestrować tongue.gif


Dla zalogowanych użytkowników zrobiłbym tak jak pisałem wyżej - na bazie danych



A co do ikonek przeczytany/nieprzeczytany post to jeśli mają one inne nazwy, to powinny się zmieniać razem ze statusem postu (przeczytany/nieprzeczytany). Jeśli tego jakimś cudem nie robią, to trzeba byłoby wysłać do przeglądarki nagłówki, żeby nie trzymał tych obrazków w cache.
ElemenT
tak jak pisalem - problem z oznaczaniem tematow w widoku jednego forum juz jest rozwiazany
problem kolejny i to dosc powazny

widok glowny forum (index) gdzie jest lista for i 1 ikonka oznaczajaca ze jakis temat (lub tematy) na konkretnym boardzie jest nowy

latwo zrobic by zaznaczala sie ikonka na czerwow (nowe tematy) po samych datach
gorzej jak wejdziesz juz do boarda, przeczytasz tematy nowe - na liscie tematow bedzie wszystko przeczytane (korzysta z sesji i zaisanych tam info co sie czytalo) a na glownej forum nadal bedzie na czerwono (bo uwzglednia daty)

niby mozna zrobic taki bajer, ze jak buduje liste tematow to przy braku wystapienia "czerwonej ikonki" bedzie stawial marker ze forum przeczytane, tylko co w momencie jak przegladamy ktora z kolei strone

nie wiem jak to rozwiazac
mam nadzieje ze problem przedstawiam jakos sensownie i zrozumiale
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.