Come implementare il flusso di attività in un social network


141

Sto sviluppando il mio social network e non ho trovato sul web esempi di implementazione del flusso di azioni degli utenti ... Ad esempio, come filtrare le azioni per ciascun utente? Come archiviare gli eventi d'azione? Quale modello di dati e modello di oggetto posso usare per il flusso di azioni e per le azioni stesse?


9
buona fortuna, questa è la domanda infinita che tutti noi vogliamo sapere, come fa Facebook a risolverlo, la risposta è molto complessa e potremmo non conoscere mai il modo più efficiente di farlo. Se trovi un buon approccio, ti preghiamo di pubblicarlo qui per essere visualizzato da altri, a proposito questo è stato discusso molte volte su SO, quindi cerca e troverai alcuni suggerimenti
JasonDavis,

1
Stream Framework è la soluzione più utilizzata: github.com/tschellenbach/Stream-Framework Vedi anche questo elenco di pacchetti: djangopackages.com/grids/g/activities
Thierry

1
In termini di personalizzazione si basa sull'analisi
Thierry,

Risposte:


242

Riepilogo : per circa 1 milione di utenti attivi e 150 milioni di attività memorizzate, lo mantengo semplice:

  • Utilizzare un database relazionale per l'archiviazione di attività uniche (1 record per attività / "cosa accaduta") Rendere i record il più compatti possibile. Struttura in modo da poter afferrare rapidamente un gruppo di attività in base all'ID attività o utilizzando un set di ID amico con vincoli temporali.
  • Pubblica gli ID attività su Redis ogni volta che viene creato un record di attività, aggiungendo l'ID a un elenco di "flussi di attività" per ogni utente amico / abbonato che dovrebbe vedere l'attività.

Eseguire una query su Redis per ottenere il flusso di attività per qualsiasi utente, quindi acquisire i dati correlati dal database in base alle esigenze. Torna a interrogare il db per tempo se l'utente deve navigare molto indietro nel tempo (se lo offri anche tu)


Uso una semplice vecchia tabella MySQL per gestire circa 15 milioni di attività.

Sembra qualcosa del genere:

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_typemi dice il tipo di attività, source_idmi dice il record a cui l'attività è correlata. Quindi, se il tipo di attività significa "preferito aggiunto", allora so che source_id si riferisce all'ID di un record preferito.

I parent_id/ parent_typesono utili per la mia app: mi dicono a cosa è correlata l'attività. Se un libro fosse preferito, parent_id / parent_type mi direbbe che l'attività si riferisce a un libro (tipo) con una determinata chiave primaria (id)

Indico (user_id, time)e cerco le attività che sono user_id IN (...friends...) AND time > some-cutoff-point. Abbandonare l'id e scegliere un diverso indice cluster potrebbe essere una buona idea - non l'ho mai provato.

Roba piuttosto semplice, ma funziona, è semplice ed è facile lavorare con il cambiamento delle tue esigenze. Inoltre, se non si utilizza MySQL, si potrebbe essere in grado di eseguire meglio l'indice.


Per un accesso più veloce alle attività più recenti, ho sperimentato Redis . Redis memorizza tutti i suoi dati in memoria, quindi non puoi mettere tutte le tue attività lì dentro, ma puoi archiviare abbastanza per la maggior parte delle schermate più colpite sul tuo sito. I 100 più recenti per ogni utente o qualcosa del genere. Con Redis nel mix, potrebbe funzionare così:

  • Crea il tuo record di attività MySQL
  • Per ogni amico dell'utente che ha creato l'attività, inserisci l'ID nel loro elenco di attività in Redis.
  • Taglia ogni elenco con gli ultimi X elementi

Redis è veloce e offre un modo per eseguire il pipeline dei comandi attraverso una connessione, quindi inviare un'attività a 1000 amici richiede millisecondi.

Per una spiegazione più dettagliata di ciò di cui sto parlando, vedi l'esempio Twitter di Redis: http://redis.io/topics/twitter-clone

Aggiornamento febbraio 2011 Al momento ho 50 milioni di attività attive e non ho cambiato nulla. Una cosa bella del fare qualcosa di simile è che usa file compatte e piccole. Sto programmando di apportare alcune modifiche che implicherebbero molte più attività e più domande su quelle attività e userò sicuramente Redis per mantenere le cose veloci. Sto usando Redis in altre aree e funziona davvero bene per alcuni tipi di problemi.

Aggiornamento luglio 2014 Siamo attivi per circa 700.000 utenti mensili attivi. Negli ultimi due anni ho usato Redis (come descritto nell'elenco puntato) per memorizzare gli ultimi 1000 ID attività per ciascun utente. Di solito ci sono circa 100 milioni di record di attività nel sistema e sono ancora memorizzati in MySQL e hanno ancora lo stesso layout. Questi record ci permettono di liberare meno memoria Redis, servono come record di dati di attività e li usiamo se gli utenti devono tornare indietro nel tempo per trovare qualcosa.

Questa non era una soluzione intelligente o particolarmente interessante, ma mi ha servito bene.


2
+1 per Redis. v2 utilizza la memoria virtuale, quindi dovrebbe essere possibile affidarsi interamente a Redis
stagas,

16
Se sono presenti più fonti di attività (aggiungi, commenta, mi piace, ecc.), Come si unisce questa tabella alle attività effettive? Usi più join sinistro (ciascuno per una tabella di attività)?
Ali Shakiba,

1
La domanda di @casey Echoing @JohnS: come si esegue JOINsulle varie activity_typetabelle? Quelle si uniscono a costose prestazioni?
Rob Sobers,

1
Qualcuno ha ricevuto risposta alla domanda di JohnS sul "JOIN". Qualcuno può pubblicare un link in cui potrebbe essere spiegato? Devo fare una cosa simile e mi sarebbe molto utile.
Waseem,

3
Nessun join. Una query per univoco activity_typeper ottenere gli altri dati necessari.
superato

21

Questa è la mia implementazione di un flusso di attività, usando mysql. Esistono tre classi: Activity, ActivityFeed, Subscriber.

L'attività rappresenta una voce di attività e la sua tabella è simile alla seguente:

id
subject_id
object_id
type
verb
data
time

Subject_idè l'id dell'oggetto che esegue l'azione, object_idl'id dell'oggetto che riceve l'azione. typee verbdescrive l'azione stessa (ad esempio, se un utente aggiunge un commento a un articolo sarebbero rispettivamente "commento" e "creato"), i dati contengono dati aggiuntivi al fine di evitare join (ad esempio, possono contenere il nome dell'oggetto e cognome, titolo e URL dell'articolo, corpo del commento ecc.).

Ogni attività appartiene a uno o più ActivityFeed e sono correlati da una tabella simile alla seguente:

feed_name
activity_id

Nella mia applicazione ho un feed per ciascun utente e un feed per ogni elemento (di solito articoli di blog), ma possono essere quello che vuoi.

Un Sottoscrittore di solito è un utente del tuo sito, ma può anche essere qualsiasi oggetto nel tuo modello di oggetto (ad esempio un articolo potrebbe essere abbonato alla feed_action del suo creatore).

Ogni iscritto appartiene a uno o più ActivityFeed e, come sopra, sono correlati da una tabella di collegamenti di questo tipo:

feed_name
subscriber_id
reason

Il reasoncampo qui spiega perché l'abbonato ha sottoscritto il feed. Ad esempio, se un utente aggiunge un segnalibro a un post sul blog, il motivo è "segnalibro". Questo mi aiuta in seguito a filtrare le azioni per le notifiche agli utenti.

Per recuperare l'attività di un abbonato, faccio un semplice join delle tre tabelle. L'unione è veloce perché seleziono poche attività grazie a una WHEREcondizione che sembra ora - time > some hours. Evito altri join grazie al campo dati nella tabella Attività.

Ulteriore spiegazione sul reasoncampo. Se, ad esempio, voglio filtrare le azioni per le notifiche e-mail all'utente e l'utente ha inserito un segnalibro in un post sul blog (e quindi si iscrive al feed dei post con il motivo "segnalibro"), non voglio che l'utente riceva notifiche e-mail sulle azioni relative a quell'elemento, mentre se commenta il post (e quindi si iscrive al feed del post con motivo 'comment'), voglio che venga informato quando altri utenti aggiungono commenti allo stesso post. Il campo del motivo mi aiuta in questa discriminazione (l'ho implementato attraverso una classe ActivityFilter), insieme alle preferenze di notifica dell'utente.


Nicolo martini volevo aggiungere un commento di risposta sull'attività e mostrarlo sotto, come è possibile con la tua struttura? dovrei aggiungere un'altra tabella o semplicemente usare lo stesso, se uguale, quali sono i tuoi suggerimenti?
Basit

Come sono le prestazioni di questa implementazione? Qualche test su grandi tavoli?
Joshua F. Rountree,

16

Esiste un formato attuale per il flusso di attività che viene sviluppato da un gruppo di persone ben note.

http://activitystrea.ms/ .

Fondamentalmente, ogni attività ha un attore (che svolge l'attività), un verbo (l'azione dell'attività), un oggetto (su cui l'attore si esibisce) e un bersaglio.

Ad esempio: Max ha pubblicato un link alla bacheca di Adam.

La loro specifica JSON ha raggiunto la versione 1.0 al momento della scrittura, che mostra lo schema dell'attività che è possibile applicare.

Il loro formato è già stato adottato da BBC, Gnip, Google Buzz Gowalla, IBM, MySpace, Opera, Socialcast, Superfeedr, TypePad, Windows Live, YIID e molti altri.


ciao @sntran So che questo post è stato anni fa, ma ho una domanda in più sul flusso di attività. C'è un modo in cui puoi dare una mano?
hiswendy,

Sicuro. Qual è la tua domanda?
Sơn Trần-Nguyễn,

La mia domanda è effettivamente pubblicata qui! link . Penso di avere una conoscenza di base del flusso di attività, ma in realtà non sono così sicuro di come implementarlo (cioè dovrei usare angular o node.js?) E da lì, come posso effettivamente CREARE un flusso di attività con API JSON in arrivo? Queste sono domande di base, ma non sono riuscito a trovare risposte online. Se puoi dare una mano, lo apprezzerei davvero. Grazie!
hiswendy,

13

Penso che una spiegazione su come funziona il sistema di notifiche su siti Web di grandi dimensioni può essere trovata nella domanda di overflow dello stack in che modo i siti Web di social network calcolano gli aggiornamenti degli amici? , nella risposta del muro di Jeremy . Suggerisce l'uso di Message Qeue e indica due software open source che lo implementano:

  1. RabbitMQ
  2. Apache QPid

Vedi anche la domanda Qual è il modo migliore per implementare un flusso di attività sociale?


1

Hai assolutamente bisogno di una coda di messaggi distribuita e performante. Ma non finisce qui, dovrai prendere decisioni su cosa archiviare come dati persistenti e cosa come transitorio ed ecc.

Ad ogni modo, amico mio, è davvero difficile se stai cercando un sistema scalabile e ad alte prestazioni. Ma, naturalmente, alcuni ingegneri generosi hanno condiviso la loro esperienza su questo. LinkedIn recentemente ha reso il suo sistema di code di messaggi Kafka open source. Prima di questo, Facebook aveva già fornito Scribe alla comunità open source. Kafka è scritto in Scala e all'inizio ci vuole del tempo per farlo funzionare, ma ho provato con un paio di server virtuali. È veramente veloce.

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

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


0

Invece di implementare il tuo, potresti cercare un servizio di terze parti utilizzato tramite un'API. Ne ho iniziato uno chiamato Collabinate ( http://www.collabinate.com ) che ha un backend di database grafico e alcuni algoritmi abbastanza sofisticati per la gestione di grandi quantità di dati in modo altamente concorrenziale e ad alte prestazioni. Sebbene non abbia l'ampiezza delle funzionalità che dicono Facebook o Twitter, è più che sufficiente per la maggior parte dei casi di utilizzo in cui è necessario creare flussi di attività, feed social o funzionalità di microblogging in un'applicazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.