Como implementar o fluxo de atividades em uma rede social


140

Estou desenvolvendo minha própria rede social e não encontrei na web exemplos de implementação o fluxo de ações dos usuários ... Por exemplo, como filtrar ações para cada usuário? Como armazenar os eventos de ação? Qual modelo de dados e modelo de objeto posso usar para o fluxo de ações e para as próprias ações?


9
boa sorte, essa é a pergunta interminável que todos queremos saber, como o facebook o faz, a resposta é muito complexa e talvez nunca saibamos a maneira mais eficiente de fazer isso. Se você encontrar uma boa abordagem, por favor, postá-lo aqui para que outros vejam, BTW isto tem sido discutido muitos muito tempo na SO então basta procurar e você vai encontrar algumas dicas
JasonDavis

1
Fluxo Framework é a solução mais amplamente utilizado: github.com/tschellenbach/Stream-Framework também ver este anúncio de pacotes: djangopackages.com/grids/g/activities
Thierry

1
Em termos de personalização É baseado na análise e aprendizagem de máquina, consulte também getstream.io/personalization
Thierry

Respostas:


241

Resumo : Para cerca de 1 milhão de usuários ativos e 150 milhões de atividades armazenadas, eu simplifico:

  • Use um banco de dados relacional para armazenar atividades exclusivas (1 registro por atividade / "coisa que aconteceu") Torne os registros o mais compactos possível. Estrutura para que você possa capturar rapidamente um lote de atividades por ID de atividade ou usando um conjunto de IDs de amigos com restrições de tempo.
  • Publique os IDs de atividade no Redis sempre que um registro de atividade for criado, adicionando o ID a uma lista de "fluxo de atividades" para cada usuário amigo / assinante que deve ver a atividade.

Consulte Redis para obter o fluxo de atividades de qualquer usuário e, em seguida, obtenha os dados relacionados do banco de dados, conforme necessário. Volte a consultar o banco de dados por tempo se o usuário precisar navegar muito no tempo (se você oferecer isso)


Eu uso uma tabela antiga simples do MySQL para lidar com cerca de 15 milhões de atividades.

Parece algo como isto:

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_typeinforma o tipo de atividade, source_idinforma o registro ao qual a atividade está relacionada. Portanto, se o tipo de atividade significa "favorito adicionado", eu sei que o source_id se refere ao ID de um registro favorito.

Os parent_id/ parent_typesão úteis para o meu aplicativo - eles me dizem a que a atividade está relacionada. Se um livro fosse favorito, parent_id / parent_type me diria que a atividade está relacionada a um livro (tipo) com uma determinada chave primária (id)

Eu indexo (user_id, time)e procuro atividades que são user_id IN (...friends...) AND time > some-cutoff-point. Abandonar o ID e escolher um índice em cluster diferente pode ser uma boa ideia - não experimentei isso.

Coisas bastante básicas, mas funcionam, são simples e são fáceis de trabalhar conforme as suas necessidades mudam. Além disso, se você não estiver usando o MySQL, poderá executar melhor em termos de índice.


Para acesso mais rápido às atividades mais recentes, experimentei o Redis . O Redis armazena todos os seus dados na memória, para que você não possa colocar todas as suas atividades nele, mas pode armazenar o suficiente para a maioria das telas mais comuns do seu site. Os 100 mais recentes para cada usuário ou algo parecido. Com Redis na mistura, pode funcionar assim:

  • Crie seu registro de atividade do MySQL
  • Para cada amigo do usuário que criou a atividade, envie o ID para sua lista de atividades no Redis.
  • Aparar cada lista com os últimos X itens

O Redis é rápido e oferece uma maneira de canalizar comandos através de uma conexão - assim, enviar uma atividade para 1.000 amigos leva milissegundos.

Para uma explicação mais detalhada do que estou falando, consulte o exemplo do Redis no Twitter: http://redis.io/topics/twitter-clone

Atualização em fevereiro de 2011 Eu tenho 50 milhões de atividades ativas no momento e não mudei nada. Uma coisa legal de fazer algo semelhante a isso é que ele usa linhas pequenas e compactas. Estou planejando fazer algumas mudanças que envolvam muito mais atividades e mais consultas dessas atividades, e definitivamente utilizarei o Redis para manter as coisas rápidas. Estou usando o Redis em outras áreas e realmente funciona bem para certos tipos de problemas.

Atualização julho de 2014 Temos cerca de 700 mil usuários ativos mensais. Nos últimos dois anos, tenho usado o Redis (como descrito na lista com marcadores) para armazenar os últimos 1000 IDs de atividade para cada usuário. Geralmente, existem cerca de 100 milhões de registros de atividades no sistema e eles ainda estão armazenados no MySQL e ainda têm o mesmo layout. Esses registros nos permitem gastar menos memória Redis, eles servem como o registro dos dados da atividade e os usamos se os usuários precisarem voltar mais no tempo para encontrar algo.

Esta não foi uma solução inteligente ou especialmente interessante, mas me serviu bem.


2
+1 para Redis. v2 usa memória virtual por isso deve ser possível confiar inteiramente em Redis
stagas

16
Se houver várias fontes de atividade (adicionar, comentar, curtir etc.), como você ingressa nesta tabela com atividades reais? Você usa várias associações à esquerda (cada uma para uma tabela de atividades)?
Ali Shakiba

1
@casey Echoing @JohnS 'pergunta - como você executa o JOINnas várias activity_typetabelas? Essas junções são caras em termos de desempenho?
22711 Rob Sobers

1
Alguém já respondeu à pergunta do JohnS sobre o "JOIN". Alguém pode postar um link onde possa ser explicado? Eu tenho que fazer algo semelhante e seria muito útil para mim.
Waseem

3
Sem junções. Uma consulta por única activity_typepara obter os outros dados necessários.
Outcassed

21

Esta é a minha implementação de um fluxo de atividades, usando o mysql. Existem três classes: Activity, ActivityFeed, Subscriber.

Activity representa uma entrada de atividade e sua tabela fica assim:

id
subject_id
object_id
type
verb
data
time

Subject_idé o ID do objeto que está executando a ação, object_ido ID do objeto que recebe a ação. typee verbdescreve a ação em si (por exemplo, se um usuário adicionar um comentário a um artigo, ele seria "comment" e "created" respectivamente), os dados conterão dados adicionais para evitar junções (por exemplo, ele pode conter o nome do assunto e sobrenome, título e URL do artigo, corpo do comentário etc.).

Cada atividade pertence a um ou mais ActivityFeeds e são relacionados por uma tabela que se parece com isso:

feed_name
activity_id

No meu aplicativo, tenho um feed para cada usuário e um feed para cada item (geralmente artigos de blog), mas eles podem ser o que você quiser.

Um Assinante geralmente é um usuário do seu site, mas também pode ser qualquer objeto no seu modelo de objeto (por exemplo, um artigo pode ser inscrito na feed_action do criador).

Cada Assinante pertence a um ou mais ActivityFeeds e, como acima, são relacionados por uma tabela de links desse tipo:

feed_name
subscriber_id
reason

O reasoncampo aqui explica por que o assinante assinou o feed. Por exemplo, se um usuário marcar uma postagem de blog, o motivo é "marcador". Isso me ajuda mais tarde a filtrar ações para notificações aos usuários.

Para recuperar a atividade de um assinante, faço uma junção simples das três tabelas. A junção é rápida porque seleciono poucas atividades graças a uma WHEREcondição que parece agora - time > some hours. Evito outras junções graças ao campo de dados na tabela Atividade.

Mais explicações em reasoncampo. Se, por exemplo, quero filtrar ações para notificações por email ao usuário e o usuário marcou uma postagem de blog (e, portanto, ele assina o feed da postagem com o motivo 'marcador'), não quero que o usuário receba enviar notificações por e-mail sobre ações nesse item, enquanto se ele comentar a postagem (e, por isso, assinar o feed da postagem com o motivo 'comentar'), desejo que ele seja notificado quando outros usuários adicionarem comentários à mesma postagem. O campo de razão me ajuda nessa discriminação (eu a implementei por meio de uma classe ActivityFilter), juntamente com as preferências de notificações do usuário.


Nicolo martini eu queria adicionar um comentário de resposta à atividade e mostrá-lo sob ela, como é possível com sua estrutura? devo adicionar outra tabela ou apenas usar o mesmo, se o mesmo, quais são as suas sugestões?
Basit

Como está o desempenho dessa implementação? Algum teste em mesas grandes?
precisa

16

Existe um formato atual para o fluxo de atividades que está sendo desenvolvido por várias pessoas conhecidas.

http://activitystrea.ms/ .

Basicamente, toda atividade tem um ator (que executa a atividade), um verbo (a ação da atividade), um objeto (no qual o ator atua) e um alvo.

Por exemplo: Max postou um link no mural de Adam.

As especificações do JSON atingiram a versão 1.0 no momento da redação, que mostra o padrão para a atividade que você pode aplicar.

Seu formato já foi adotado pela BBC, Gnip, Google Buzz Gowalla, IBM, MySpace, Opera, Socialcast, Superfeedr, TypePad, Windows Live, YIID e muitos outros.


oi @sntran Eu sei que este post foi anos atrás, mas tenho uma pergunta mais sobre o fluxo de atividades. Existe uma maneira de você ajudar?
hiswendy

Certo. Qual a sua pergunta?
Sần Trần-Nguyễn

Minha pergunta está realmente publicada aqui! link . Acho que tenho um entendimento básico do fluxo de atividades, mas não tenho muita certeza de como implementá-lo (por exemplo, devo usar angular ou node.js?) API de entrada JSON? Essas são perguntas básicas, mas não consegui encontrar respostas on-line. Se você puder ajudar, eu realmente aprecio isso. Obrigado!
hiswendy


1

Você absolutamente precisa de um desempenho e fila de mensagens distribuídas. Mas não termina aí, você terá que tomar decisões sobre o que armazenar como dados persistentes e o que são transitórios e etc.

Enfim, é realmente uma tarefa difícil, meu amigo, se você está atrás de um sistema escalável e de alto desempenho. Mas, é claro, alguns engenheiros generosos compartilharam sua experiência sobre isso. O LinkedIn recentemente criou seu sistema de fila de mensagens Kafka de código aberto. Antes disso, o Facebook já havia fornecido o Scribe à comunidade de código aberto. O Kafka é escrito em Scala e, inicialmente, leva algum tempo para ser executado, mas eu testei com alguns servidores virtuais. É muito rápido.

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

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


0

Em vez de criar o seu próprio, você pode procurar um serviço de terceiros usado por meio de uma API. Comecei um chamado Collabinate ( http://www.collabinate.com ), que possui um back-end de banco de dados de gráficos e alguns algoritmos bastante sofisticados para lidar com grandes quantidades de dados de maneira altamente simultânea e de alto desempenho. Embora não tenha a amplitude de funcionalidade que o Facebook ou o Twitter possuem, é mais do que suficiente para a maioria dos casos de uso em que você precisa criar fluxos de atividade, feeds sociais ou funcionalidade de microblog em um aplicativo.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.