ruby-on-rails android-activity social-networking

ruby on rails - ¿Cuál es la mejor manera de implementar un flujo de actividad social?



ruby-on-rails android-activity (13)

Me interesa escuchar sus opiniones sobre cuál es la mejor manera de implementar un flujo de actividad social (Facebook es el ejemplo más famoso). Los problemas / desafíos involucrados son:

  • Diferentes tipos de actividades (publicación, comentario ...).
  • Diferentes tipos de objetos (post, comentario, foto ..)
  • 1-n usuarios involucrados en diferentes roles ("El usuario x respondió al comentario de User y en la publicación Z del usuario")
  • Diferentes vistas del mismo elemento de actividad ("usted comentó .." frente a "su amigo x comentó" frente a "usuario x comentó ..." => 3 representaciones de una actividad de "comentario")

... y algo más, especialmente si lo lleva a un alto nivel de sofisticación, como lo hace Facebook, por ejemplo, combinando varios elementos de actividad en uno ("los usuarios x, y, z comentaron en esa foto"

Cualquier comentario o sugerencia sobre patrones, documentos, etc. sobre los enfoques más flexibles, eficientes y poderosos para implementar dicho sistema, modelo de datos, etc., sería apreciado.

Aunque la mayoría de los problemas son agnósticos de la plataforma, es probable que termine implementando un sistema de este tipo en Ruby on Rails


Comencé a implementar un sistema como este ayer, aquí es donde tengo que ...

Creé una clase StreamEvent con las propiedades Id , ActorId , TypeId , Date , ObjectId y un hashtable de pares clave / valor de Detalles adicionales. Esto se representa en la base de datos mediante una tabla StreamEvent ( Id , ActorId , TypeId , Date , ObjectId ) y una tabla StreamEventDetails ( StreamEventId , DetailKey , DetailValue ).

El ActorId , TypeId y ObjectId permiten que un evento Subject-Verb-Object sea capturado (y luego consultado). Cada acción puede dar como resultado la creación de varias instancias de StreamEvent.

Luego, he creado una subclase para cada tipo de evento de StreamEvent , por ejemplo, LoginEvent , PictureCommentEvent . Cada una de estas subclases tiene propiedades más específicas del contexto, como PictureId , ThumbNail , CommenText , etc. (lo que sea necesario para el evento) que realmente se almacenan como pares clave / valor en la tabla hashtable / StreamEventDetail.

Cuando extraigo estos eventos de la base de datos, uso un método de fábrica (basado en el TypeId ) para crear la clase StreamEvent correcta.

Cada subclase de StreamEvent tiene un método Render ( context As StreamContext ) que envía el evento a la pantalla según la clase StreamContext pasada. La clase StreamContext permite configurar las opciones según el contexto de la vista. Si miras Facebook, por ejemplo, tu feed de noticias en la página de inicio muestra los nombres completos (y enlaces a su perfil) de todos los involucrados en cada acción, mientras que al buscar un feed de amigos solo ves su nombre (pero los nombres completos de otros actores) .

Todavía no he implementado una fuente agregada (página de inicio de Facebook) pero imagino que crearé una tabla AggregateFeed que tiene los campos UserId , StreamEventId que se rellena en función de algún tipo de ''Hmmm, puede que encuentre este interesante algoritmo''.

Cualquier comentario sería masivamente apreciado.


Creo que el enfoque de Plurk es interesante: suministran su línea de tiempo completa en un formato que se parece mucho a los gráficos de acciones de Google Finance.

Puede valer la pena mirar a Ning para ver cómo funciona una red social. Las páginas de desarrollador parecen especialmente útiles.


Después de implementar flujos de actividad para habilitar las funciones de redes sociales, microblogging y colaboración en varias aplicaciones, me di cuenta de que la funcionalidad básica es bastante común y podría convertirse en un servicio externo que usted utiliza a través de una API. Si está incorporando el flujo a una aplicación de producción y no tiene necesidades únicas o profundamente complejas, la mejor manera de hacerlo es utilizar un servicio comprobado. Definitivamente, recomendaría esto para aplicaciones de producción sobre cómo rodar su propia solución simple sobre una base de datos relacional.

Mi empresa Collabinate ( http://www.collabinate.com ) surgió de esta realización, y hemos implementado un motor de flujo de actividad escalable y de alto rendimiento en la parte superior de una base de datos gráfica para lograrlo. En realidad, utilizamos una variante del algoritmo Graphity (adaptado del trabajo inicial de @RenePickhardt que también proporcionó una respuesta aquí) para construir el motor.

Si desea alojar el motor usted mismo o requiere una funcionalidad especializada, el código principal es en realidad de código abierto para fines no comerciales, por lo que puede echar un vistazo.




He creado tal sistema y tomé este enfoque:

Tabla de base de datos con las siguientes columnas: ID, ID de usuario, tipo, datos, tiempo.

  • userId es el usuario que generó la actividad.
  • tipo es el tipo de actividad (es decir, escribió una publicación en el blog, agregó una foto, comentó la foto del usuario)
  • Los datos son un objeto serializado con metadatos para la actividad donde puede colocar lo que desee.

Esto limita las búsquedas / búsquedas que puede hacer en las fuentes, a los usuarios, el tiempo y los tipos de actividad, pero en una fuente de actividades de tipo Facebook, esto no es realmente limitante. Y con los índices correctos en la tabla, las búsquedas son rápidas .

Con este diseño, tendría que decidir qué metadatos debe requerir cada tipo de evento. Por ejemplo, una actividad de feed para una nueva foto podría verse algo como esto:

{id:1, userId:1, type:PHOTO, time:2008-10-15 12:00:00, data:{photoId:2089, photoName:A trip to the beach}}

Se puede ver que, aunque el nombre de la foto ciertamente se almacena en alguna otra tabla que contiene las fotos, y puedo recuperar el nombre desde allí, duplicaré el nombre en el campo de metadatos, porque no quiere hacerlo cualquier combinación en otras tablas de base de datos si desea velocidad. Y para mostrar, digamos 200, diferentes eventos de 50 usuarios diferentes, necesita velocidad.

Luego tengo clases que amplían una clase básica de FeedActivity para representar los diferentes tipos de entradas de actividad. La agrupación de eventos también se incluiría en el código de representación, para evitar la complejidad de la base de datos.


Hemos abierto nuestro enfoque: https://github.com/tschellenbach/Stream-Framework Actualmente es la biblioteca de código abierto más grande destinada a resolver este problema.

El mismo equipo que creó Stream Framework también ofrece una API alojada, que maneja la complejidad para usted. Eche un vistazo a getstream.io. Hay clientes disponibles para Node, Python, Rails y PHP.

Además, eche un vistazo a esta publicación de alta escalabilidad donde explicamos algunas de las decisiones de diseño involucradas: http://highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your-high-traffic-feeds.html

Este tutorial te ayudará a configurar un sistema como el feed de Pinterest usando Redis. Es muy fácil empezar.

Para obtener más información sobre el diseño de feeds, recomiendo leer algunos de los artículos en los que basamos a Feedly:

Aunque Stream Framework está basado en Python, no sería demasiado difícil de usar desde una aplicación Ruby. Simplemente puede ejecutarlo como un servicio y pegar una pequeña API de HTTP en frente de él. Estamos considerando agregar una API para acceder a Feedly desde otros idiomas. Sin embargo, en este momento tendrás que cumplir tu propia función.


Los mayores problemas con los flujos de eventos son la visibilidad y el rendimiento; debe restringir los eventos que se muestran para que sean solo los interesantes para ese usuario en particular, y debe mantener la cantidad de tiempo que lleva ordenar e identificar esos eventos de forma manejable. He construido una red social pequeña; Descubrí que a pequeña escala, mantener una tabla de "eventos" en una base de datos funciona, pero que se convierte en un problema de rendimiento bajo una carga moderada.

Con una gran cantidad de mensajes y usuarios, probablemente es mejor ir con un sistema de mensajería, donde los eventos se envían como mensajes a perfiles individuales. Esto significa que no puede suscribirse fácilmente a las secuencias de eventos de las personas y ver los eventos anteriores con mucha facilidad, pero simplemente está procesando un pequeño grupo de mensajes cuando necesita renderizar la secuencia para un usuario en particular.

Creo que este fue el defecto de diseño original de Twitter. Recuerdo haber leído que estaban llegando a la base de datos para acceder y filtrar sus eventos. Esto tenía todo que ver con la arquitectura y nada que ver con Rails, que (desafortunadamente) dio origen al meme "ruby no escala". Hace poco vi una presentación en la que el desarrollador usó el servicio Simple Queue Service de Amazon como backend de mensajería para una aplicación similar a la de Twitter que tendría capacidades de escalamiento mucho mayores. Puede que valga la pena ver SQS como parte de su sistema, si sus cargas son lo suficientemente altas. .


Resolví esto hace unos meses, pero creo que mi implementación es demasiado básica.
Creé los siguientes modelos:

HISTORY_TYPE ID - The id of the history type NAME - The name (type of the history) DESCRIPTION - A description HISTORY_MESSAGES ID HISTORY_TYPE - A message of history belongs to a history type MESSAGE - The message to print, I put variables to be replaced by the actual values HISTORY_ACTIVITY ID MESSAGE_ID - The message ID to use VALUES - The data to use

Ejemplo

MESSAGE_ID_1 => "User %{user} created a new entry" ACTIVITY_ID_1 => MESSAGE_ID = 1, VALUES = {user: "Rodrigo"}


Si decide que va a implementar en Rails, tal vez encuentre útil el siguiente complemento:

ActivityStreams: http://github.com/face/activity_streams/tree/master

Si no hace nada más, podrá ver una implementación, tanto en términos del modelo de datos, como en la API proporcionada para impulsar y extraer actividades.


Si está dispuesto a usar un software separado, sugiero el servidor Graphity que resuelve exactamente el problema para las secuencias de actividad (basándose en la base de datos del gráfico neo4j).

Los algoritmos se han implementado como un servidor REST independiente para que pueda alojar su propio servidor para entregar flujos de actividad: http://www.rene-pickhardt.de/graphity-server-for-social-activity-streams-released-gplv3/

En el documento y en el punto de referencia, demostré que la recuperación de secuencias de noticias depende solo de forma lineal de la cantidad de elementos que desea recuperar sin ninguna redundancia que obtendría al desnormalizar los datos:

http://www.rene-pickhardt.de/graphity-an-efficient-graph-model-for-retrieving-the-top-k-news-feeds-for-users-in-social-networks/

En el enlace anterior, se encuentran los screencasts y un punto de referencia de este enfoque (que muestra que la gravedad puede recuperar más de 10k flujos por segundo).


Tuve un enfoque similar al de heyman: una tabla desnormalizada que contiene todos los datos que se mostrarían en un flujo de actividad determinado. Funciona bien para un sitio pequeño con actividad limitada.

Como se mencionó anteriormente, es probable que enfrente problemas de escalabilidad a medida que el sitio crece. Personalmente, no estoy preocupado por los problemas de escalamiento en este momento. Me preocuparé por eso más adelante.

Es obvio que Facebook ha hecho un gran trabajo de escalado, por lo que te recomiendo que leas su blog de ingeniería, ya que tiene un montón de contenido excelente -> http://www.facebook.com/notes.php?id=9445547199

He estado buscando mejores soluciones que la tabla desnormalizada que mencioné anteriormente. Otra forma que he encontrado de lograr esto es condensar todo el contenido que estaría en un flujo de actividad dado en una sola fila. Puede almacenarse en XML, JSON o en algún formato serializado que pueda leer su aplicación. El proceso de actualización también sería simple. Tras la actividad, coloque la nueva actividad en una cola (tal vez utilizando Amazon SQS o algo más) y luego haga una encuesta continua en la cola para el siguiente elemento. Agarre ese elemento, analícelo y coloque su contenido en el objeto de alimentación apropiado almacenado en la base de datos.

Lo bueno de este método es que solo necesita leer una única tabla de base de datos cada vez que se solicita ese feed en particular, en lugar de tomar una serie de tablas. Además, le permite mantener una lista finita de actividades, ya que puede extraer el elemento de actividad más antiguo cada vez que actualice la lista.

¡Espero que esto ayude! :)


// one entry per actual event events { id, timestamp, type, data } // one entry per event, per feed containing that event events_feeds { event_id, feed_id }

Cuando se crea el evento, decida en qué fuentes aparece y agréguelas a events_feeds. Para obtener un feed, seleccione de events_feeds, únase a eventos, ordene por marca de tiempo. El filtrado y la agregación se pueden hacer sobre los resultados de esa consulta. Con este modelo, puede cambiar las propiedades del evento después de la creación sin trabajo adicional.