web-dev-qa-db-fra.com

Quelle est la meilleure façon de mettre en œuvre un flux d'activité sociale?

J'aimerais connaître votre opinion sur la meilleure façon de mettre en œuvre un flux d'activités sociales (Facebook en est l'exemple le plus célèbre). Les problèmes/défis impliqués sont:

  • Différents types d'activités (poster, commenter ..)
  • Différents types d'objets (post, commentaire, photo ..)
  • 1-n utilisateurs impliqués dans différents rôles ("L'utilisateur x a répondu au commentaire de l'utilisateur y sur le post Z de l'utilisateur")
  • Différentes vues du même élément d'activité ("vous avez commenté .." vs "votre ami x a commenté" vs "utilisateur x commenté .." => 3 représentations d'une activité "commentaire")

.. et quelques-uns de plus, en particulier si vous prenez un niveau de sophistication élevé, comme Facebook, par exemple, combinant plusieurs activités en un seul ("les utilisateurs x, y et z ont commenté cette photo"

Toute pensée ou indication sur les modèles, les articles, etc. sur les approches les plus flexibles, efficaces et performantes pour mettre en œuvre un tel système, modèle de données, etc. serait appréciée.

Bien que la plupart des problèmes soient liés à la plate-forme, il est probable que je finisse par mettre en œuvre un tel système sur Ruby sur Rails

264
mort

J'ai créé un tel système et j'ai adopté cette approche:

Table de base de données avec les colonnes suivantes: id, userId, type, data, time.

  • serId est l'utilisateur qui a généré l'activité
  • type est le type de l'activité (c'est-à-dire écrire un article de blog, ajouter une photo, commenter la photo de l'utilisateur)
  • data est un objet sérialisé avec des méta-données pour l'activité où vous pouvez mettre ce que vous voulez

Cela limite les recherches/recherches que vous pouvez effectuer dans les flux, aux utilisateurs, aux types d'heure et d'activité, mais dans un flux d'activité de type facebook, cela n'est pas vraiment limitant. Et avec des index corrects sur la table, les recherches sont rapides .

Avec cette conception, vous devez décider des métadonnées que chaque type d’événement doit exiger. Par exemple, une activité de fil pour une nouvelle photo pourrait ressembler à ceci:

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

Vous pouvez voir que, même si le nom de la photo est très certainement stocké dans une autre table contenant les photos, et que je pourrais récupérer le nom à partir de là, je vais dupliquer le nom dans le champ de métadonnées, car vous ne voulez pas le faire. toute jointure sur d'autres tables de base de données si vous voulez la vitesse. Et pour afficher, disons 200, différents événements de 50 utilisateurs différents, vous avez besoin de rapidité.

Ensuite, j'ai des classes qui étend une classe de base FeedActivity pour restituer les différents types d'entrées d'activité. Le regroupement d'événements serait également intégré au code de rendu afin d'éviter toute complexité de la base de données.

143
heyman

C’est une très bonne présentation décrivant comment Etsy.com a conçu leurs flux d’activités. C’est le meilleur exemple que j’ai trouvé sur le sujet, même s’il n’est pas spécifique à Rails.

http://www.slideshare.net/danmckinley/etsy-activity-feeds-architecture

116
Mark Kennedy

Nous avons ouvert la source de notre approche: https://github.com/tschellenbach/Stream-Framework C'est actuellement la plus grande bibliothèque open source visant à résoudre ce problème.

La même équipe qui a construit Stream Framework propose également une API hébergée, qui gère la complexité pour vous. Jetez un œil à getstream.io Il existe des clients pour Node, Python, Rails et PHP.

En outre, jetez un œil à cet article à forte évolutivité où nous avons expliqué certaines des décisions de conception prises: http://highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your- fort trafic-feeds.html

Ce tutoriel vous aidera à configurer un système comme celui de Pinterest avec Redis. C'est assez facile de commencer avec.

Pour en savoir plus sur la conception des aliments, je vous recommande vivement de lire certains des articles sur lesquels nous avons basé Feedly:

Bien que Stream Framework soit Python, il ne serait pas trop difficile de l'utiliser depuis une Ruby. Vous pouvez simplement l'exécuter en tant que service et y placer un petit L'API HTTP http devant nous.Nous envisageons d'ajouter une API pour accéder à Feedly à partir d'autres langues. Pour le moment, vous devrez jouer le vôtre.

44
Thierry

Les principaux problèmes liés aux flux d'événements sont la visibilité et les performances. vous devez limiter les événements affichés à ceux qui sont intéressants pour cet utilisateur particulier, et vous devez conserver le temps nécessaire pour effectuer un tri et identifier ces événements. J'ai construit un petit réseau social. J'ai constaté que, à petite échelle, conserver une table des "événements" dans une base de données fonctionne, mais que cela devient un problème de performances sous une charge modérée.

Avec un plus grand nombre de messages et d'utilisateurs, il est probablement préférable d'utiliser un système de messagerie dans lequel les événements sont envoyés sous forme de messages à des profils individuels. Cela signifie que vous ne pouvez pas facilement vous abonner aux flux d'événements des personnes et voir les événements précédents très facilement, mais vous restituez simplement le rendu d'un petit groupe de messages lorsque vous devez rendre le flux pour un utilisateur particulier.

Je pense que c’était là le défaut de conception original de Twitter. Je me souviens avoir lu qu’ils avaient utilisé la base de données pour filtrer et filtrer leurs événements. Cela avait tout à voir avec l'architecture et rien à voir avec Rails, qui (malheureusement) a donné naissance au meme "Ruby not scale". J'ai récemment vu une présentation dans laquelle le développeur utilisait le Simple Queue Service d'Amazon comme serveur de messagerie pour une application de type Twitter qui aurait des capacités de mise à l'échelle beaucoup plus grandes. , si vos charges sont assez élevées.

19
Tim Howland

Si vous souhaitez utiliser un logiciel distinct, je suggère le serveur Graphity, qui résout exactement le problème des flux d’activités (en vous basant sur la base de données graphique neo4j).

Les algorithmes ont été implémentés en tant que serveur autonome REST afin que vous puissiez héberger votre propre serveur afin de fournir des flux d'activité: http://www.rene-pickhardt.de/graphity- server-for-social-activity-streams-release-gplv3 /

Dans l'article et le benchmark, j'ai montré que la récupération de flux de nouvelles dépend uniquement de la quantité d'éléments que vous souhaitez récupérer sans aucune redondance que vous obtiendriez de la dénormalisation des données:

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

Sur le lien ci-dessus, vous trouverez des captures d’écran et un repère de cette approche (montrant que graphité peut extraire plus de 10 000 flux par seconde).

12
Rene Pickhardt
 // une entrée par événement réel 
 événements {
 id, horodatage, type, données 
} 
 
 // un entrée par événement, par flux contenant cet événement 
 events_feeds {
 event_id, feed_id 
} 

Lorsque l'événement est créé, décidez dans quels flux il apparaît et ajoutez-les à events_feeds. Pour obtenir un flux, sélectionnez events_feeds, joignez des événements, commandez par horodatage. Le filtrage et l'agrégation peuvent ensuite être effectués sur les résultats de cette requête. Avec ce modèle, vous pouvez modifier les propriétés de l'événement après la création sans travail supplémentaire.

10
jedediah

J'ai commencé à mettre en place un système comme celui-ci hier, voici où je dois ...

J'ai créé une classe StreamEvent avec les propriétés Id , ActorId , TypeId , Date , ObjectId et une table de hachage de paires supplémentaires Détails . Ceci est représenté dans la base de données par un StreamEvent table ( Id , ActorId , TypeId , Date , ObjectId ) et une table StreamEventDetails ( StreamEventId , DetailKey , DetailValue ).

Le ActorId , TypeId et ObjectId permet à un événement Subject-Verb-Object d'être capturé (et ultérieurement interrogé). Chaque action peut entraîner la création de plusieurs instances de StreamEvent.

J'ai ensuite créé une sous-classe pour StreamEvent pour chaque type d'événement, par exemple. LoginEvent, PictureCommentEvent. Chacune de ces sous-classes a des propriétés plus spécifiques au contexte, telles que PictureId , ThumbNail , CommenText , etc. (ce qui est requis pour l'événement) qui sont actuellement stockés sous forme de paires clé/valeur dans la table hashtable/StreamEventDetail.

Lors de l'extraction de ces événements de la base de données, j'utilise une méthode fabrique (basée sur le TypeId ) ) pour créer la classe StreamEvent appropriée.

Chaque sous-classe de StreamEvent a une méthode de rendu ( As StreamContext) qui renvoie l’événement à l’écran en fonction du StreamContext classe. La classe StreamContext permet de définir des options en fonction du contexte de la vue. Si vous regardez par exemple Facebook, votre fil d'actualités sur la page d'accueil répertorie les noms complets (et les liens vers leur profil) de toutes les personnes impliquées dans chaque action, alors que lorsque vous regardez le flux d'un ami, vous ne voyez que son prénom (mais les noms complets des autres acteurs). .

Je n'ai pas encore implémenté de flux global (page d'accueil Facebook) mais j'imagine que je vais créer une table AggregateFeed qui contient les champs UserId , StreamEventId qui est rempli en fonction d'une sorte de "Hmmm, vous pourriez trouver cet algorithme intéressant".

Tous les commentaires seraient massivement appréciés.

10
jammus

Si vous décidez que vous allez implémenter dans Rails, vous trouverez peut-être le plugin suivant utile:

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

Si rien d'autre ne vous empêche d'aller voir une implémentation, à la fois en termes de modèle de données et d'API fournie pour les activités de transfert et d'extraction.

8
Alderete

Il y a deux balados sur un tel flux d'activité:

Ces solutions n'incluent pas toutes vos exigences, mais cela devrait vous donner quelques idées.

5
Benjamin Crouzier

Je pense que l'approche de Plurk est intéressante: ils fournissent l'intégralité de votre chronologie dans un format qui ressemble beaucoup aux tableaux boursiers de Google Finance.

Il peut être intéressant de regarder Ning pour voir comment fonctionne un réseau de réseau social. Les pages développeur sont particulièrement utiles.

3
warren

Après avoir implémenté des flux d'activité pour activer les fonctionnalités de flux sociaux, de micro-blogging et de collaboration dans plusieurs applications, je me suis rendu compte que les fonctionnalités de base étaient assez courantes et pouvaient devenir un service externe que vous utilisiez via une API. Si vous intégrez le flux dans une application de production et que vous n'avez pas de besoins uniques ou profondément complexes, utiliser un service éprouvé peut être la meilleure solution. Je le recommanderais certainement pour les applications de production plutôt que d'appliquer votre propre solution simple à une base de données relationnelle.

Mon entreprise Collabinate ( http://www.collabinate.com ) est née de cette constatation et a mis en place un moteur de flux d’activités évolutif et performant sur une base de données de graphes. Nous avons en fait utilisé une variante de l'algorithme Graphity (adapté des travaux antérieurs de @RenePickhardt, qui a également fourni une réponse ici) pour construire le moteur.

Si vous souhaitez héberger vous-même le moteur ou si vous avez besoin de fonctionnalités spécialisées, le code principal est en fait une source ouverte à des fins non commerciales. Vous pouvez donc y jeter un coup d'œil.

2
Mafuba

J'ai résolu ce problème il y a quelques mois, mais je pense que mon implémentation est trop basique.
J'ai créé les modèles suivants:

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

Exemple

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