source plantilla para paginas pagina open foros foro descargar create crear como php mysql forum

php - plantilla - paginas para crear foros



Foros de PHP: cómo hacer frente a discusiones/temas/publicaciones no leídas (7)

¿Por qué estás preocupado?

No veo ningún problema con ninguna E / S para obtener los subprocesos no leídos. No tiene que ser en vivo. Un retraso de 15 minutos basado en un valor de caché funcionaría.

Así que para hilos no leídos solo

Pseudo código ..

$result = SELECT id,viewcount from my_forum_threads $cache->setThreads($result[''id''],$result[''viewcount'']);

Luego, en una carga de página, solo obtiene los valores de caché en lugar de consultar la base de datos nuevamente. Realmente no es un gran problema en absoluto.

La página promedio en mi sitio web toma 20 consultas mysql. Cuando caché es solo de dos a cuatro consultas.

Sé que esta pregunta se ha formulado aquí un par de veces, pero ninguna de las respuestas me ha gustado. Esto se debe a que casi todos implican un enorme proceso de lectura / escritura relacionado con la base de datos, que me gustaría evitar a toda costa.

Sobre discusiones / temas / publicaciones no leídas, hay mucho que pensar. No sé cómo los sistemas de foros como MyBB , vBulletin , Invision Power Board , Vanilla , phpBB , etc., resuelven ese problema, por lo que me gustaría leerles su experiencia con eso. Sé que usar una tabla de base de datos solo para eso es la forma más sencilla, pero eso implicaría una enorme lectura / escritura cuando la comunidad tenga más de 10,000 miembros y 1000 temas nuevos cada mes. Es difícil, pero debería haber una manera de evitar la sobrecarga del servidor.

Entonces, ¿cuáles son las mejores prácticas para este problema, así como la forma en que otros sistemas de foros lo enfrentan?


Casi todos los foros que conozco usarán algún tipo de marca de tiempo de referencia para determinar si un hilo / mensaje debe considerarse como "no leído" o no. Esta marca de tiempo generalmente es la fecha / hora de la última acción que realizó en su visita anterior al foro.

Así que te quedas es decir. una marca de tiempo de previous_last_action y last_action en su tabla de usuarios, last_action se actualiza en cada acción del usuario, la columna previous_last_action se establece una vez para last_action al iniciar sesión (o al crear una nueva sesión, si tiene la funcionalidad de "Recordarme"). Para determinar si un hilo / mensaje no se ha leído, comparará la marca de tiempo de la creación (o actualización) de ese hilo / mensaje con el valor en previous_last_action para el usuario que ha iniciado sesión actualmente.


Hay otro.

Otra forma de almacenar datos detallados leídos / no leídos para una estructura jerárquica de foro (tablero> sección> hilo, etc.). Lo hace sin a) tener que rellenar previamente la información leída / no leída, yb) sin tener que almacenar más de U * (M / 2) filas en su peor caso, donde U es el número de usuarios, y M es el número total de publicaciones en la base de datos (y generalmente mucho, mucho menos que esto)

He investigado este tema hace un tiempo. Encontré que SMF / phpBB "hace trampa" un poco en la forma en que almacenan el historial de lectura de los usuarios. Su esquema admite el almacenamiento de la última marca de tiempo o el ID de mensaje que se marcó como leído en un foro, foro, subforo, tema (o visto directamente por el navegador), así:

[user_id, board, last_msg_id, last_timestamp]

[user_id, board, forum, last_msg_id, last_timestamp]

[user_id, board, forum, subforum, last_msg_id, last_timestamp]

[user_id, board, forum, subforum, topic, last_msg_id, last_timestamp]

Esto permite a los usuarios marcar tableros específicos, foros, temas, etc., como "leídos". Sin embargo, requiere una acción por parte del usuario (ya sea leyendo o haciendo clic en "marcar como leído"), y en el caso de phpBB, no le da la granularidad de decir "He visto esto específico mensaje, pero no ese mensaje específico ". También obtiene la situación en la que lee el último mensaje en un tema primero (viendo la última actividad en un hilo), y se supone inmediatamente que ha leído el resto del hilo.

Funciona para SMF y phpBB para almacenar cosas como esta porque es raro que alguna vez estés viendo solo una publicación (las vistas predeterminadas están configuradas para más de 20 publicaciones en la última página de un tema). Sin embargo, para más foros con hilos (especialmente los foros en los que estás viendo los mensajes uno a la vez), esto no es lo ideal. Es probable que los usuarios de este sistema se preocupen mucho si han leído un mensaje pero no otro, y podrían considerar engorroso que solo se pueda marcar una sección completa como leída, cuando en realidad solo querían que algunos se marcaran como leídos.

Almacena mensajes en tuplas como esta: [user_id, lower_msg_id, upper_msg_id]

El registro de historial de usuario se mantiene de la siguiente manera:

Al ver la página, una función busca si user_id tiene un registro donde current_msg_id está entre lower_msg_id y upper_msg_id. Si lo ha hecho, entonces se lee esta página y no es necesario realizar ninguna acción. Si no es así, entonces se debe emitir otra consulta, esta vez para determinar si current_msg_id es uno menos que lower_msg_id (current_msg_id == lower_msg_id-1), o uno más que upper_msg_id (current_msg_id == upper_msg_id +1). Este es el caso en el que aumentamos nuestro límite de "lectura" o "visto" en 1. Si estamos a una distancia de lower_msg_id o uppper_msg_id, entonces aumentamos la tupla en 1 en esa dirección. Si no estamos ampliando nuestro rango de tuplas, insertamos una nueva tupla, [user_id, current_msg_id, current_msg_id].

El caso de la esquina es cuando dos rangos de tuplas se aproximan. En este caso, al buscar entre el límite inferior de la tupla y el límite superior de la tupla, fusione los dos límites estableciendo el límite superior de la tupla inferior en el límite superior de la tupla superior, y elimine la tupla superior.

Ejemplo de código en PHP:

function seen_bounds( $usr_id, $msg_id ) { # mysql escape $usr_id = mres( $usr_id ); $msg_id = mres( $msg_id ); $seen_query = " SELECT msb.id, msb.lower_msg_id, msb.upper_msg_id FROM msgs_seen_bounds msb WHERE $msg_id BETWEEN msb.lower_msg_id AND msb.upper_msg_id AND msb.usr_id = $usr_id LIMIT 1; "; # See if this post already exists within a given # seen bound. $seen_row = query($seen_query, ROW); if($seen_row == 0) { # Has not been seen, try to detect if we''re "near" # another bound (and we can grow that bound to include # this post). $lower_query = " SELECT msb.id, msb.lower_msg_id, msb.upper_msg_id FROM msgs_seen_bounds msb WHERE msb.upper_msg_id = ($msg_id - 1) AND msb.usr_id = $usr_id LIMIT 1; "; $upper_query = " SELECT msb.id, msb.lower_msg_id, msb.upper_msg_id FROM msgs_seen_bounds msb WHERE msb.lower_msg_id = ($msg_id + 1) AND msb.usr_id = $usr_id LIMIT 1; "; $lower = query($lower_query, ROW); $upper = query($upper_query, ROW); if( $lower == 0 && $upper == 0 ) { # No bounds exist for or near this. We''ll insert a single-ID # bound $saw_query = " INSERT INTO msgs_seen_bounds (usr_id, lower_msg_id, upper_msg_id) VALUES ($usr_id, $msg_id, $msg_id) ; "; query($saw_query, NONE); } else { if( $lower != 0 && $upper != 0 ) { # Found "near" bounds both on the upper # and lower bounds. $update_query = '' UPDATE msgs_seen_bounds SET upper_msg_id = '' . $upper[''upper_msg_id''] . '' WHERE msgs_seen_bounds.id = '' . $lower[''id''] . '' ; ''; $delete_query = '' DELETE FROM msgs_seen_bounds WHERE msgs_seen_bounds.id = '' . $upper[''id''] . '' ; ''; query($update_query, NONE); query($delete_query, NONE); } else { if( $lower != 0 ) { # Only found lower bound, update accordingly. $update_query = '' UPDATE msgs_seen_bounds SET upper_msg_id = '' . $msg_id . '' WHERE msgs_seen_bounds.id = '' . $lower[''id''] . '' ; ''; query($update_query, NONE); } if( $upper != 0 ) { # Only found upper bound, update accordingly. $update_query = '' UPDATE msgs_seen_bounds SET lower_msg_id = '' . $msg_id . '' WHERE msgs_seen_bounds.id = '' . $upper[''id''] . '' ; ''; query($update_query, NONE); } } } } else { # Do nothing, already seen. } }

Buscar publicaciones no leídas es encontrar donde current_msg_id no existe entre ningún lower_msg_id y upper_msg_id para un usuario determinado (una consulta NO EXISTA en términos de SQL). No es la consulta más eficiente cuando se implementa en una base de datos relacional, pero puede resolverse mediante una indexación agresiva. Por ejemplo, la siguiente es una consulta SQL para contar las publicaciones no leídas de un usuario determinado, agrupadas por el área de discusión ("elemento") en la que se encuentran las publicaciones:

$count_unseen_query = " SELECT msgs.item as id, count(1) as the_count FROM msgs WHERE msgs.usr != " . $usr_id . " AND msgs.state != ''deleted'' AND NOT EXISTS ( SELECT 1 FROM msgs_seen_bounds msb WHERE msgs.id BETWEEN msb.lower_msg_id AND msb.upper_msg_id AND msb.usr_id = " . $usr_id . " ) GROUP BY msgs.item ;

Cuantos más usuarios lean en el foro, más amplios serán los límites marcados como leídos por cada tupla, y habrá que almacenar menos tuplas. Los usuarios pueden obtener un recuento preciso de lecturas frente a no leídas, y se pueden agregar fácilmente para leer leídas o no leídas en cada foro, subforum, tema, etc.

Dado un pequeño foro de aproximadamente 2000 publicaciones, las siguientes son las estadísticas de uso con respecto al número de tuplas almacenadas, ordenadas por el número de veces que los usuarios han iniciado sesión (actividad aproximada del usuario). La columna "num_bounds" es el número de tuplas necesarias para almacenar el historial de visualización "num_posts_read" del usuario.

id num_log_entries num_bounds num_posts_read num_posts 479 584 11 2161 228 118 461 6 2167 724 487 119 34 2093 199 499 97 6 2090 309 476 71 139 481 82 480 33 92 167 26 486 33 256 757 154 496 31 108 193 51 490 31 80 179 61 475 28 129 226 47 491 22 22 1207 24 502 20 100 232 65 493 14 73 141 5 489 14 12 1517 22 498 10 72 132 17

No he visto esta implementación en particular en ningún foro, pero sí en mi propia aplicación, y es muy pequeña. Me interesaría si alguien más lo ha implementado, o lo ha visto implementado en otro lugar, particularmente en un foro grande y / o activo.

Saludos,

Kaiden


He leído todas las respuestas y vine con una idea que puede ser la mejor combinación para este tema (aunque no hay código).
Esta idea es una mezcla de todas sus ideas y la poca experiencia que tengo en la programación.
Aproximadamente el 95% de los usuarios (las estadísticas se obtuvieron de un administrador del foro y sus registros del foro) leen los temas del foro directamente a la última publicación (o página) y no regresan, lean las publicaciones de la primera página (o solo la primera publicación) ) y luego vaya a la última página, o leen todo el hilo desde el principio hasta el final y, si se dan la vuelta, ya habían leído esa parte. Así que una buena solución funcionaría así:
Creo que si hacemos una tienda, para cada usuario, para cada subproceso, la marca de tiempo de la última publicación que el usuario vio (y, si corresponde, la primera publicación que vio el usuario, incluso si eso no fuera útil) podríamos obtener En algún lugar con esto. El sistema es bastante simple y es casi como phpbb''s. También sería útil marcar la última publicación que vimos para continuar en la siguiente (en lugar de tener que considerar toda la página como leída). Y, como cada hilo tiene su propia id. No hay necesidad de organizar como lo hace phpbb.


No es exactamente una respuesta de PHP, pero así es como lo hacemos en nuestro foro basado en asp.net (estoy afiliado a este producto, revelando eso debido a las reglas)

  1. Usamos cookies , no la base de datos.
    • Desventaja de las cookies, no de "dispositivo cruzado" (visitar desde otra computadora muestra todo como no leído)
    • Ventaja - no hay grandes DB de lecturas / escrituras. ¡Y el seguimiento funciona también para usuarios "invitados"! Esto es impresionante
  2. Almacenamos una cookie con los { topicID, lastReadMessageID } para cada tema que el usuario visita.
  3. Si los datos de un tema en particular no se encuentran en la cookie, asumimos que el tema es:
    • completamente no leído (si el último mensaje del tema es mayor que MAX lastReadMessageID de (2)
    • leer completamente (si no)

Esto tiene algunos defectos menores, pero hace el trabajo.

PD. Además, algunos podrían decir que el uso de cookies deja basura en la computadora del usuario (yo personalmente odio esto), pero descubrimos que un usuario promedio rastrea alrededor de 20 temas principales, por lo que toma alrededor de 10 bytes por tema, por lo que toma menos de 200 bytes. en el disco duro del usuario.


No hay muchas opciones.

  1. Marca cada hilo de lector por cada usuario.

    • Desventajas: muchas filas en foros muy activos.
    • Ventajas: Todo usuario sabe con post ha leído o no.
  2. Marca cada hilo no leído por cada usuario.

    • Desventajas: mucho espacio con filas "no leídas" si hay inactividad de muchos usuarios
    • Soluciones: agregue una marca de tiempo de por vida y elimine registros antiguos con un cron
    • Ventajas: Todo usuario sabe con post ha leído o no.
  3. Use las marcas de tiempo para determinar si se muestra como no leído o no.

    • Desventajas: los usuarios no saben con los hilos reales no leídos, las marcas solo muestran los "nuevos encabezados" desde el último inicio de sesión
    • Ventaja: ahorra espacio

La otra alternativa es mezclar soluciones, es decir,

1 y 3) muestran el hilo como "no leído" si no tienen más de X días y no hay una fila marcada como leída por el usuario. Las filas de "lectura" se pueden eliminar cuando son X día más antiguas sin afectar nada.

Ventajas

  • menos espacio utilizado para determinar hilos no leídos

Desventajas

  • Crea un cron que mantenga limpio el sistema.
  • Los usuarios no saben si leen hilos más viejos que x días.

Ventajas

  • Cada usuario sabe qué "nuevas publicaciones" ha leído o no.

Una respuesta rápida sobre cómo (creo) IPB lo hace:

Todas las publicaciones anteriores a la cantidad de configuración (30 días predeterminados) se marcan automáticamente como leídas. Un cronjob recorta estos de cada usuario para mantener el tamaño manejable.

Todas las publicaciones con menos de 30 días de antigüedad se rastrean como una entrada JSON para cada categoría de ID de usuario +. Ej: 12 categorías con 1000 usuarios activos = máximo de 12,000 filas.

Hay un campo de "recuento no leído" para búsquedas rápidas para, por ejemplo, la página de inicio del foro, o en cualquier otro lugar, solo se necesita un número.

Podría estar completamente apagado en el almacenamiento de MySQL real. No pude encontrar documentación sobre esto, pero busqué en la base de datos y vi una tabla que parecía / parecía / leía / no leída (tabla: core_item_markers, para referencia). Pero soy positivo en el modelo híbrido age / mysql.