Cómo implementar el flujo de actividad en una red social


140

Estoy desarrollando mi propia red social, y no he encontrado en la web ejemplos de implementación del flujo de acciones de los usuarios ... Por ejemplo, ¿cómo filtrar acciones para cada usuario? ¿Cómo almacenar los eventos de acción? ¿Qué modelo de datos y modelo de objetos puedo usar para la secuencia de acciones y para las acciones mismas?


9
buena suerte, esta es la pregunta interminable que todos queremos saber, cómo lo logra Facebook, la respuesta es muy compleja y es posible que nunca sepamos la forma más eficiente de hacerlo. Si encuentra un BUEN enfoque, publíquelo aquí para que otros lo vean, por cierto, esto se ha discutido muchas veces en SO, así que solo busque y encontrará algunos consejos
JasonDavis el

1
Stream Framework es la solución más utilizada: github.com/tschellenbach/Stream-Framework Consulte también esta lista de paquetes: djangopackages.com/grids/g/activities
Thierry

1
En términos de personalización, se basa en análisis y aprendizaje automático. Consulte también getstream.io/personalization
Thierry,

Respuestas:


241

Resumen : para aproximadamente 1 millón de usuarios activos y 150 millones de actividades almacenadas, lo mantengo simple:

  • Use una base de datos relacional para almacenar actividades únicas (1 registro por actividad / "cosa que sucedió") Haga los registros lo más compactos posible. Estructura para que pueda tomar rápidamente un lote de actividades por ID de actividad o mediante el uso de un conjunto de ID de amigos con limitaciones de tiempo.
  • Publique los ID de actividad en Redis siempre que se cree un registro de actividad, agregando el ID a una lista de "flujo de actividad" para cada usuario que sea un amigo / suscriptor que debería ver la actividad.

Consulte Redis para obtener el flujo de actividad de cualquier usuario y luego tome los datos relacionados de la base de datos según sea necesario. Vuelva a consultar la base de datos por tiempo si el usuario necesita navegar muy atrás en el tiempo (incluso si ofrece esto)


Utilizo una tabla simple de MySQL para tratar con unos 15 millones de actividades.

Se parece a esto:

id             
user_id       (int)
activity_type (tinyint)
source_id     (int)  
parent_id     (int)
parent_type   (tinyint)
time          (datetime but a smaller type like int would be better) 

activity_typeme dice el tipo de actividad, source_idme dice el registro con el que está relacionada la actividad. Entonces, si el tipo de actividad significa "favorito agregado", entonces sé que source_id se refiere a la ID de un registro favorito.

Los parent_id/ parent_typeson útiles para mi aplicación: me dicen con qué está relacionada la actividad. Si se favoreció un libro, entonces parent_id / parent_type me diría que la actividad se relaciona con un libro (tipo) con una clave primaria (id) dada

Indico (user_id, time)y busco actividades que sean user_id IN (...friends...) AND time > some-cutoff-point. Quitar la identificación y elegir un índice agrupado diferente podría ser una buena idea, no he experimentado con eso.

Bastante básico, pero funciona, es simple y es fácil trabajar con él a medida que cambian sus necesidades. Además, si no está usando MySQL, podría hacerlo mejor en cuanto a índice.


Para un acceso más rápido a las actividades más recientes, he estado experimentando con Redis . Redis almacena todos sus datos en la memoria, por lo que no puede poner todas sus actividades allí, pero podría almacenar lo suficiente para la mayoría de las pantallas comúnmente visitadas en su sitio. Los 100 más recientes para cada usuario o algo así. Con Redis en la mezcla, podría funcionar así:

  • Crea tu registro de actividad MySQL
  • Para cada amigo del usuario que creó la actividad, inserte el ID en su lista de actividades en Redis.
  • Recorte cada lista a los últimos X elementos

Redis es rápido y ofrece una forma de canalizar comandos a través de una conexión, por lo que llevar una actividad a 1000 amigos lleva milisegundos.

Para una explicación más detallada de lo que estoy hablando, vea el ejemplo de Twitter de Redis: http://redis.io/topics/twitter-clone

Actualización de febrero de 2011 Tengo 50 millones de actividades activas en este momento y no he cambiado nada. Una cosa buena de hacer algo similar a esto es que usa filas pequeñas y compactas. Estoy planeando hacer algunos cambios que involucrarían muchas más actividades y más consultas de esas actividades y definitivamente usaré Redis para mantener las cosas rápidas. Estoy usando Redis en otras áreas y realmente funciona bien para ciertos tipos de problemas.

Actualización de julio de 2014 Hasta 700,000 usuarios activos mensuales. Durante los últimos dos años, he estado usando Redis (como se describe en la lista con viñetas) para almacenar los últimos 1000 ID de actividad para cada usuario. Por lo general, hay alrededor de 100 millones de registros de actividad en el sistema y todavía están almacenados en MySQL y siguen siendo el mismo diseño. Estos registros nos permiten salir con menos memoria de Redis, sirven como registro de datos de actividad y los usamos si los usuarios necesitan retroceder más en el tiempo para encontrar algo.

Esta no fue una solución inteligente o especialmente interesante, pero me ha servido bien.


2
+1 para Redis. v2 usa memoria virtual, por lo que debería ser posible confiar completamente en Redis
stagas

16
Si hay múltiples fuentes de actividad (agregar, comentar, dar me gusta, etc.), ¿cómo une esta tabla con actividades reales? ¿Utiliza múltiples combinaciones izquierdas (cada una para una tabla de actividades)?
Ali Shakiba

1
Pregunta de @casey Echoing @JohnS: ¿cómo se realiza JOINen las distintas activity_typetablas? ¿Son esas uniones costosas en cuanto al rendimiento?
Rob Sobers

1
¿Alguien tiene respuesta a la pregunta de JohnS sobre "JOIN"? ¿Alguien puede publicar un enlace donde pueda explicarse? Tengo que hacer algo similar y sería muy útil para mí.
Waseem

3
No se une. Una consulta por único activity_typepara obtener los otros datos que necesita.
superado el

21

Esta es mi implementación de un flujo de actividad, usando mysql. Hay tres clases: Activity, ActivityFeed, Subscriber.

La actividad representa una entrada de actividad, y su tabla se ve así:

id
subject_id
object_id
type
verb
data
time

Subject_ides la identificación del objeto que realiza la acción, object_idla identificación del objeto que recibe la acción. typey verbdescribe la acción en sí (por ejemplo, si un usuario agrega un comentario a un artículo, sería "comentario" y "creado" respectivamente), los datos contienen datos adicionales para evitar uniones (por ejemplo, puede contener el nombre del sujeto y apellido, el título del artículo y la URL, el cuerpo del comentario, etc.).

Cada actividad pertenece a uno o más feeds de actividad, y están relacionados por una tabla que se ve así:

feed_name
activity_id

En mi aplicación, tengo un feed para cada usuario y un feed para cada elemento (generalmente artículos de blog), pero pueden ser lo que quieras.

Un suscriptor suele ser un usuario de su sitio, pero también puede ser cualquier objeto en su modelo de objetos (por ejemplo, un artículo podría suscribirse a la acción feed_action de su creador).

Cada suscriptor pertenece a uno o más feeds de actividad y, como se indicó anteriormente, están relacionados por una tabla de enlaces de este tipo:

feed_name
subscriber_id
reason

El reasoncampo aquí explica por qué el suscriptor ha suscrito el feed. Por ejemplo, si un usuario marca una publicación de blog, el motivo es 'marcar'. Esto me ayuda más tarde en el filtrado de acciones para notificaciones a los usuarios.

Para recuperar la actividad de un suscriptor, hago una simple combinación de las tres tablas. La unión es rápida porque selecciono pocas actividades gracias a una WHEREcondición que parece ahora - time > some hours. Evito otras uniones gracias al campo de datos en la tabla Actividad.

Explicación adicional en el reasoncampo. Si, por ejemplo, quiero filtrar acciones para notificaciones de correo electrónico para el usuario, y el usuario marcó una publicación de blog (y se suscribe al feed de publicación con el motivo 'marcador'), no quiero que el usuario reciba notificaciones por correo electrónico sobre acciones en ese elemento, mientras que si comenta la publicación (y se suscribe al feed de la publicación con el motivo 'comentario') quiero que se le notifique cuando otros usuarios agreguen comentarios a la misma publicación. El campo de razón me ayuda en esta discriminación (lo implementé a través de una clase ActivityFilter), junto con las preferencias de notificaciones del usuario.


Nicolo martini, quería agregar un comentario de respuesta sobre la actividad y mostrarla debajo, ¿cómo es posible con su estructura? ¿Debo agregar otra tabla o simplemente usar la misma, si es la misma, entonces cuáles son sus sugerencias?
Basit

¿Cómo es el rendimiento de esta implementación? ¿Alguna prueba en mesas grandes?
Joshua F. Rountree

16

Hay un formato actual para el flujo de actividad que está siendo desarrollado por un grupo de personas bien conocidas.

http://activitystrea.ms/ .

Básicamente, cada actividad tiene un actor (que realiza la actividad), un verbo (la acción de la actividad), un objeto (sobre el cual el actor realiza) y un objetivo.

Por ejemplo: Max ha publicado un enlace al muro de Adam.

Las especificaciones de JSON han alcanzado la versión 1.0 en el momento de la escritura, que muestra el patrón de la actividad que puede aplicar.

Su formato ya ha sido adoptado por BBC, Gnip, Google Buzz Gowalla, IBM, MySpace, Opera, Socialcast, Superfeedr, TypePad, Windows Live, YIID y muchos otros.


hola @sntran Sé que esta publicación fue hace años, pero tengo una pregunta más sobre el flujo de actividad. ¿Hay alguna manera de ayudar?
hiswendy

Por supuesto. ¿Cuál es tu pregunta?
Sơn Trần-Nguyễn

¡Mi pregunta está publicada aquí! enlace . Creo que tengo una comprensión básica del flujo de actividad, pero realmente no estoy tan seguro de cómo implementarlo (es decir, ¿se supone que debo usar angular o node.js?) Y a partir de ahí, ¿cómo puedo CREAR un flujo de actividad con API JSON entrante? Estas son preguntas tan básicas, pero no pude encontrar ninguna respuesta en línea. Si puede ayudar, realmente lo agradecería. ¡Gracias!
hiswendy

13

Creo que se puede encontrar una explicación sobre cómo funciona el sistema de notificaciones en sitios web grandes en la pregunta de desbordamiento de pila. ¿Cómo calculan los sitios web de redes sociales las actualizaciones de amigos? , en la respuesta de Jeremy Wall . Sugiere el uso de Message Qeue e indica dos softwares de código abierto que lo implementan:

  1. RabbitMQ
  2. Apache QPid

Vea también la pregunta ¿Cuál es la mejor manera de implementar un flujo de actividad social?


1

Absolutamente necesita una cola de mensajes distribuida y eficiente. Pero no termina allí, tendrá que tomar decisiones sobre qué almacenar como datos persistentes y qué como transitorios, etc.

De todos modos, es realmente una tarea difícil, amigo mío, si buscas un sistema escalable y de alto rendimiento. Pero, por supuesto, algunos ingenieros generosos han compartido su experiencia en esto. LinkedIn recientemente creó su sistema de cola de mensajes Kafka de código abierto. Antes de eso, Facebook ya había proporcionado Scribe a la comunidad de código abierto. Kafka está escrito en Scala y al principio lleva un tiempo ejecutarlo, pero lo probé con un par de servidores virtuales. Es realmente rapido.

http://blog.linkedin.com/2011/01/11/open-source-linkedin-kafka/

http://incubator.apache.org/kafka/index.html


0

En lugar de rodar el tuyo, puedes buscar un servicio de terceros utilizado a través de una API. Comencé uno llamado Collabinate ( http://www.collabinate.com ) que tiene un backend de base de datos de gráficos y algunos algoritmos bastante sofisticados para manejar grandes cantidades de datos de una manera altamente concurrente y de alto rendimiento. Si bien no tiene la amplitud de funcionalidad que dicen Facebook o Twitter, es más que suficiente para la mayoría de los casos de uso en los que necesita construir flujos de actividad, feeds sociales o funcionalidad de microblogging en una aplicación.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.