webentwicklung-frage-antwort-db.com.de

Wie kann ein sozialer Aktivitätsstrom am besten implementiert werden?

Ich bin daran interessiert, Ihre Meinung zu erfahren, wie ein sozialer Aktivitätsstrom am besten umgesetzt werden kann (Facebook ist das bekannteste Beispiel). Probleme/Herausforderungen sind:

  • Verschiedene Arten von Aktivitäten (Posten, Kommentieren ...)
  • Verschiedene Arten von Objekten (Post, Kommentar, Foto ..)
  • 1-n Benutzer, die an verschiedenen Rollen beteiligt sind ("Benutzer x hat auf den Kommentar von Benutzer y zum Z-Beitrag des Benutzers geantwortet")
  • Verschiedene Ansichten desselben Aktivitätselements ("Sie haben kommentiert ..." vs. "Ihr Freund hat kommentiert ..." vs. "Benutzer hat kommentiert ..." => 3 Darstellungen einer "Kommentar" -Aktivität)

.. und noch einiges mehr, besonders wenn Sie es auf ein hohes Niveau bringen, wie Facebook zum Beispiel, wenn Sie mehrere Aktivitätselemente zu einem kombinieren ("Benutzer x, y und z haben dieses Foto kommentiert").

Über Gedanken oder Hinweise zu Mustern, Papieren usw. zu den flexibelsten, effizientesten und leistungsfähigsten Ansätzen zur Implementierung eines solchen Systems, Datenmodells usw. würde ich mich freuen.

Obwohl die meisten Probleme plattformunabhängig sind, besteht die Möglichkeit, dass ich ein solches System auf Ruby on Rails) implementiere

264
mort

Ich habe ein solches System geschaffen und ich habe diesen Ansatz gewählt:

Datenbanktabelle mit folgenden Spalten: id, userId, type, data, time.

  • serId ist der Benutzer, der die Aktivität generiert hat
  • Typ ist der Typ der Aktivität (d. h. schrieb einen Blogbeitrag, fügte ein Foto hinzu, kommentierte das Foto des Benutzers)
  • data ist ein serialisiertes Objekt mit Metadaten für die Aktivität, in die Sie alles eingeben können, was Sie möchten

Dies beschränkt die Such-/Suchvorgänge, die Sie in den Feeds durchführen können, auf Benutzer, Zeit und Aktivitätstypen. In einem Aktivitäts-Feed vom Facebook-Typ ist dies jedoch nicht wirklich einschränkend. Und mit den richtigen Indizes in der Tabelle sind die Suchvorgänge schnell .

Bei diesem Entwurf müssten Sie entscheiden, welche Metadaten für jeden Ereignistyp erforderlich sind. Eine Feed-Aktivität für ein neues Foto könnte beispielsweise so aussehen:

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

Sie können sehen, dass, obwohl der Name des Fotos mit Sicherheit in einer anderen Tabelle gespeichert ist, die die Fotos enthält, und ich den Namen von dort abrufen konnte, ich den Namen im Metadatenfeld duplizieren werde, weil Sie dies nicht möchten Verknüpfungen mit anderen Datenbanktabellen, wenn Sie Geschwindigkeit wünschen. Und um beispielsweise 200 verschiedene Ereignisse von 50 verschiedenen Benutzern anzuzeigen, benötigen Sie Geschwindigkeit.

Dann habe ich Klassen, die eine grundlegende FeedActivity-Klasse zum Rendern der verschiedenen Typen von Aktivitätseinträgen erweitern. Die Gruppierung von Ereignissen würde ebenfalls im Rendering-Code erstellt, um die Komplexität der Datenbank zu verringern.

143
heyman

Dies ist eine sehr gute Präsentation, die beschreibt, wie Etsy.com ihre Aktivitätsströme aufgebaut hat. Es ist das beste Beispiel, das ich zu diesem Thema gefunden habe, obwohl es nicht Rails spezifisch ist.

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

116
Mark Kennedy

Wir haben unseren Ansatz als Open-Source-Lösung entwickelt: https://github.com/tschellenbach/Stream-Framework Dies ist derzeit die größte Open-Source-Bibliothek, die dieses Problem lösen soll.

Das gleiche Team, das Stream Framework erstellt hat, bietet auch eine gehostete API, die die Komplexität für Sie handhabt. Schauen Sie sich getstream.io an. Es gibt Clients für Node, Python, Rails und PHP).

Schauen Sie sich auch diesen Beitrag zur hohen Skalierbarkeit an, in dem wir einige der beteiligten Entwurfsentscheidungen erläutern: http://highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your- High-Traffic-Feeds.html

Dieses Tutorial hilft Ihnen dabei, ein System wie den Feed von Pinterest mit Redis einzurichten. Der Einstieg ist ganz einfach.

Um mehr über Feed-Design zu erfahren, empfehle ich dringend, einige der Artikel zu lesen, auf denen Feedly basiert:

Obwohl das Stream Framework auf Python basiert, wäre die Verwendung mit einer Ruby App nicht allzu schwierig. Sie könnten es einfach als Dienst ausführen und ein kleines Stück davon behalten http API davor. Wir überlegen, eine API für den Zugriff auf Feedly aus anderen Sprachen hinzuzufügen. Im Moment müssen Sie jedoch Ihre eigene Rolle spielen.

44
Thierry

Die größten Probleme mit Ereignisströmen sind Sichtbarkeit und Leistung. Sie müssen die angezeigten Ereignisse so einschränken, dass sie nur für diesen bestimmten Benutzer interessant sind, und Sie müssen die Zeit, die zum Sortieren und Identifizieren dieser Ereignisse erforderlich ist, überschaubar halten. Ich habe ein kleines soziales Netzwerk aufgebaut. Ich fand, dass es in kleinen Mengen funktioniert, eine "Ereignisse" -Tabelle in einer Datenbank zu führen, aber dass es unter mäßiger Last zu einem Leistungsproblem kommt.

Bei einem größeren Strom von Nachrichten und Benutzern ist es wahrscheinlich am besten, ein Nachrichtensystem zu verwenden, bei dem Ereignisse als Nachrichten an einzelne Profile gesendet werden. Dies bedeutet, dass Sie die Ereignisströme von Personen nicht einfach abonnieren und frühere Ereignisse nicht einfach anzeigen können. Sie rendern jedoch einfach eine kleine Gruppe von Nachrichten, wenn Sie den Stream für einen bestimmten Benutzer rendern müssen.

Ich glaube, dies war der ursprüngliche Designfehler von Twitter. Ich erinnere mich, dass sie die Datenbank aufgerufen und ihre Ereignisse gefiltert haben. Dies hatte alles mit Architektur zu tun und nichts mit Rails, aus dem (leider) das Mem "Ruby does scale" hervorging. Ich habe kürzlich eine Präsentation gesehen, in der der Entwickler Amazons Simple Queue Service als Messaging-Backend für eine Twitter-ähnliche Anwendung mit weitaus höheren Skalierungsfähigkeiten verwendete. Es kann sich lohnen, sich mit SQS als Teil Ihres Systems zu befassen , wenn Ihre Lasten hoch genug sind.

19
Tim Howland

Wenn Sie bereit sind, eine separate Software zu verwenden, empfehle ich den Graphity-Server, der genau das Problem für Aktivitätsströme löst (aufbauend auf der neo4j-Graphendatenbank).

Die Algorithmen wurden als eigenständiger REST Server implementiert, sodass Sie Ihren eigenen Server hosten können, um Aktivitätsströme zu liefern: http://www.rene-pickhardt.de/graphity- server-for-social-activity-streams-released-gplv3 /

In der Arbeit und im Benchmark habe ich gezeigt, dass das Abrufen von Nachrichtenströmen nur linear von der Anzahl der Elemente abhängt, die Sie abrufen möchten, ohne dass es zu Redundanzen kommt, wenn Sie die Daten denormalisieren:

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

Auf dem obigen Link finden Sie Screencasts und einen Benchmark dieses Ansatzes (der zeigt, dass Graphity in der Lage ist, mehr als 10.000 Streams pro Sekunde abzurufen).

12
Rene Pickhardt
 // ein Eintrag pro aktuellem Ereignis 
 Ereignisse {
 ID, Zeitstempel, Typ, Daten 
} 
 
 // ein Eintrag Eintrag pro Ereignis, pro Feed, der dieses Ereignis enthält 
 events_feeds {
 event_id, feed_id 
} 

Entscheiden Sie beim Erstellen des Ereignisses, in welchen Feeds es angezeigt wird, und fügen Sie diese zu events_feeds hinzu. Um einen Feed zu erhalten, wählen Sie aus events_feeds, nehmen Sie an Events teil und sortieren Sie nach Zeitstempel. Anschließend können die Ergebnisse dieser Abfrage gefiltert und aggregiert werden. Mit diesem Modell können Sie die Ereigniseigenschaften nach der Erstellung ohne zusätzlichen Aufwand ändern.

10
jedediah

Ich habe gestern angefangen, ein solches System zu implementieren. Hier muss ich ...

Ich habe eine StreamEvent -Klasse mit den Eigenschaften Id , ActorId , erstellt. TypeId , Date , ObjectId und eine Hashtabelle mit zusätzlichen Details Schlüssel/Wert-Paare. Dies wird in der Datenbank durch eine StreamEvent -Tabelle ( Id , ActorId , TypeId , Date , ObjectId ) und eine StreamEventDetails -Tabelle ( StreamEventId , DetailKey , DetailValue ).

Die ActorId , TypeId und ObjectId erlauben ein Subjekt-Verb-Objekt Ereignis, das erfasst (und später abgefragt) werden soll. Jede Aktion kann dazu führen, dass mehrere StreamEvent-Instanzen erstellt werden.

Ich habe dann für jeden Ereignistyp eine Unterklasse für StreamEvent erstellt, z. LoginEvent, PictureCommentEvent. Jede dieser Unterklassen verfügt über kontextspezifischere Eigenschaften wie PictureId , ThumbNail , CommenText usw. (was auch immer für das Ereignis erforderlich ist), die tatsächlich als Schlüssel/Wert-Paare in der Tabelle hashtable/StreamEventDetail gespeichert sind.

Beim Abrufen dieser Ereignisse aus der Datenbank verwende ich eine Factory-Methode (basierend auf der TypeId ), um die richtige StreamEvent-Klasse zu erstellen.

Jede Unterklasse von StreamEvent verfügt über eine Render ( - Kontext As StreamContext) -Methode, die das Ereignis basierend auf dem übergebenen StreamContext auf dem Bildschirm ausgibt Klasse. Mit der StreamContext-Klasse können Optionen basierend auf dem Kontext der Ansicht festgelegt werden. Wenn Sie sich beispielsweise Facebook ansehen, werden in Ihrem Newsfeed auf der Startseite die vollständigen Namen (und Links zu deren Profil) aller an jeder Aktion Beteiligten aufgeführt. Wenn Sie hingegen den Feed eines Freundes ansehen, sehen Sie nur dessen Vornamen (aber die vollständigen Namen anderer Akteure). .

Ich habe noch keinen aggregierten Feed (Facebook-Startseite) implementiert, aber ich stelle mir vor, ich erstelle eine AggregateFeed -Tabelle mit den Feldern UserId , StreamEventId , das auf einer Art 'Hmmm, vielleicht findest du diesen interessanten' Algorithmus basiert.

Alle Kommentare würden massiv geschätzt.

10
jammus

Wenn Sie sich für eine Implementierung in Rails entscheiden, ist das folgende Plugin möglicherweise hilfreich:

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

Wenn nichts anderes angegeben ist, können Sie sich eine Implementierung ansehen, sowohl im Hinblick auf das Datenmodell als auch auf die API, die für Push- und Pull-Aktivitäten bereitgestellt wird.

8
Alderete

Es gibt zwei Railscasts zu einem solchen Activity Stream:

Diese Lösungen enthalten nicht alle Ihre Anforderungen, sollten Ihnen jedoch einige Anregungen geben.

5

Ich denke Plurks Ansatz ist interessant: Sie liefern Ihre gesamte Timeline in einem Format, das den Aktiencharts von Google Finance sehr ähnlich sieht.

Es kann sich lohnen, sich Ning anzusehen, um zu sehen, wie ein soziales Netzwerk funktioniert. Die Entwickler Seiten sehen besonders hilfreich aus.

3
warren

Nachdem ich Activity Streams implementiert hatte, um Social Feeds, Microblogging und Funktionen für die Zusammenarbeit in mehreren Anwendungen zu aktivieren, wurde mir klar, dass die Basisfunktionalität recht häufig ist und in einen externen Dienst umgewandelt werden kann, den Sie über eine API verwenden. Wenn Sie den Stream in eine Produktionsanwendung integrieren und keine einzigartigen oder äußerst komplexen Anforderungen haben, ist die Verwendung eines bewährten Dienstes möglicherweise der beste Weg. Ich würde dies definitiv für Produktionsanwendungen empfehlen, bei denen Sie Ihre eigene einfache Lösung auf eine relationale Datenbank rollen.

Meine Firma Collabinate ( http://www.collabinate.com ) ist aus dieser Erkenntnis hervorgegangen, und wir haben eine skalierbare, hochleistungsfähige Activity Stream-Engine auf einer Graphendatenbank implementiert, um dies zu erreichen. Wir verwendeten tatsächlich eine Variante des Graphity-Algorithmus (angepasst aus der frühen Arbeit von @RenePickhardt, der auch hier eine Antwort lieferte), um die Engine zu bauen.

Wenn Sie die Engine selbst hosten möchten oder spezielle Funktionen benötigen, ist der Kerncode Open Source für nichtkommerzielle Zwecke. Sie können also gerne einen Blick darauf werfen.

2
Mafuba

Ich habe das vor ein paar Monaten gelöst, aber ich denke, meine Implementierung ist zu einfach.
Ich habe folgende Modelle erstellt:

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

Beispiel

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