Как реализовать ленту активности в социальной сети


142

Разрабатываю собственную социальную сеть, и я не нашел в сети примеров реализации потока действий пользователей ... Например, как отфильтровать действия для каждого пользователя? Как сохранить события действия? Какую модель данных и объектную модель я могу использовать для потока действий и для самих действий?


9
удачи, это бесконечный вопрос, который мы все хотим знать, как Facebook справляется с этим, ответ очень сложный, и мы, возможно, никогда не узнаем наиболее эффективный способ сделать это. Если вы найдете ХОРОШИЙ подход, опубликуйте его здесь для просмотра другими, кстати, это уже много раз обсуждалось на SO, так что просто ищите, и вы найдете несколько советов
JasonDavis

1
Stream Framework - наиболее широко используемое решение: github.com/tschellenbach/Stream-Framework. См. Также этот список пакетов: djangopackages.com/grids/g/activities
Thierry,

1
С точки зрения персонализации, он основан на аналитике и машинном обучении. Также см. Getstream.io/personalization
Тьерри,

Ответы:


244

Резюме : для примерно 1 миллиона активных пользователей и 150 миллионов сохраненных действий я делаю это простым:

  • Используйте реляционную базу данных для хранения уникальных действий (1 запись на действие / «событие, которое произошло»). Сделайте записи максимально компактными. Структурируйте так, чтобы вы могли быстро захватить группу действий по идентификатору активности или с помощью набора идентификаторов друзей с ограничениями по времени.
  • Публикуйте идентификаторы активности в Redis всякий раз, когда создается запись активности, добавляя идентификатор в список «потока активности» для каждого пользователя, который является другом / подписчиком, который должен видеть активность.

Запросите Redis, чтобы получить поток активности для любого пользователя, а затем при необходимости получить связанные данные из базы данных. Вернитесь к запросу базы данных по времени, если пользователю нужно просмотреть далеко назад во времени (если вы даже предлагаете это)


Я использую простую старую таблицу MySQL для обработки около 15 миллионов операций.

Это выглядит примерно так:

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_typeсообщает мне тип действия, source_idсообщает мне запись, к которой относится действие. Итак, если тип действия означает «добавленный в избранное», то я знаю, что source_id относится к идентификатору избранной записи.

parent_id/ parent_typeПолезны для моего приложения - они говорят мне , что деятельность связана с. Если книга была добавлена ​​в избранное, то parent_id / parent_type сообщит мне, что действие относится к книге (типу) с заданным первичным ключом (id).

Я индексирую (user_id, time)и запрашиваю действия, которые есть user_id IN (...friends...) AND time > some-cutoff-point. Отказ от идентификатора и выбор другого кластерного индекса может быть хорошей идеей - я не экспериментировал с этим.

Довольно простые вещи, но они работают, они просты, и с ними легко работать, когда ваши потребности меняются. Кроме того, если вы не используете MySQL, вы можете лучше работать с индексами.


Для более быстрого доступа к последним действиям я экспериментировал с Redis . Redis хранит все свои данные в памяти, поэтому вы не можете поместить туда все свои действия, но вы можете сохранить достаточно для большинства часто посещаемых экранов на вашем сайте. Последние 100 для каждого пользователя или что-то в этом роде. С Redis в миксе это может работать так:

  • Создайте свою запись активности MySQL
  • Для каждого друга пользователя, создавшего действие, поместите идентификатор в их список действий в Redis.
  • Обрезать каждый список до последних X элементов

Redis работает быстро и предлагает способ конвейерной передачи команд через одно соединение, поэтому передача активности 1000 друзьям занимает миллисекунды.

Для более подробного объяснения того, о чем я говорю, см. Пример Twitter Redis: http://redis.io/topics/twitter-clone

Обновление от февраля 2011 г. У меня 50 миллионов активных действий, и я ничего не изменил. В том, чтобы делать что-то подобное, хорошо то, что они используют компактные, маленькие строки. Я планирую внести некоторые изменения, которые повлекут за собой гораздо больше действий и больше запросов об этих действиях, и я обязательно буду использовать Redis для ускорения работы. Я использую Redis в других областях, и он действительно хорошо работает для определенных типов проблем.

Обновление июль 2014 г. У нас около 700 тыс. Активных пользователей в месяц. Последние пару лет я использую Redis (как описано в маркированном списке) для хранения последних 1000 идентификаторов действий для каждого пользователя. Обычно в системе около 100 миллионов записей активности, они по-прежнему хранятся в MySQL и имеют тот же формат. Эти записи позволяют нам обойтись меньшим объемом памяти Redis, они служат для записи данных об активности, и мы используем их, если пользователям нужно перейти на более раннюю страницу во времени, чтобы что-то найти.

Это не было умным или особенно интересным решением, но оно сослужило мне хорошую службу.


2
+1 для Redis. v2 использует виртуальную память, поэтому должна быть возможность полностью полагаться на Redis
stagas

16
Если существует несколько источников активности (добавление, комментарий, лайк и т. Д.), Как вы объедините эту таблицу с фактическими действиями? Используете ли вы несколько соединений слева (каждое для таблицы активности)?
Али Шакиба

1
@casey Повторяя вопрос @JohnS - как вы выполняете упражнение JOINна разных activity_typeстолах? Эти соединения дороги с точки зрения производительности?
Роб Соберс

1
Есть ли у кого-нибудь ответ на вопрос JohnS о «ПРИСОЕДИНЕНИИ». Может ли кто-нибудь опубликовать ссылку, где это можно объяснить? Я должен сделать то же самое, и это было бы мне очень полезно.
Васим

3
Нет присоединений. Один запрос на каждый уникальный, activity_typeчтобы получить другие данные, которые вам нужны.
отвергнут

21

Это моя реализация потока активности с использованием mysql. Существует три класса: Activity, ActivityFeed, Subscriber.

Действие представляет собой запись действия, и его таблица выглядит следующим образом:

id
subject_id
object_id
type
verb
data
time

Subject_idэто идентификатор объекта, выполняющего действие, object_idидентификатор объекта, который получает действие. typeи verbописывает само действие (например, если пользователь добавляет комментарий к статье, они будут «комментировать» и «созданы» соответственно), данные содержат дополнительные данные, чтобы избежать объединений (например, они могут содержать имя темы и фамилия, заголовок и URL статьи, текст комментария и т. д.).

Каждое Activity принадлежит одному или нескольким ActivityFeed, и они связаны таблицей, которая выглядит следующим образом:

feed_name
activity_id

В моем приложении у меня есть один канал для каждого пользователя и один канал для каждого элемента (обычно статьи в блогах), но они могут быть какими угодно.

Подписчик обычно является пользователем вашего сайта, но он также может быть любым объектом в вашей объектной модели (например, статья может быть подписана на feed_action его создателя).

Каждый подписчик принадлежит одному или нескольким ActivityFeed, и, как и выше, они связаны таблицей ссылок такого типа:

feed_name
subscriber_id
reason

В этом reasonполе объясняется, почему подписчик подписался на ленту. Например, если пользователь добавляет в закладки сообщение в блоге, причина в «закладке». Это помогает мне в дальнейшем фильтровать действия для уведомлений пользователей.

Чтобы получить активность для подписчика, я просто объединяю три таблицы. Присоединение происходит быстро, потому что я выбираю несколько действий благодаря WHEREусловию, которое сейчас выглядит как - time > some hours. Я избегаю других объединений благодаря полю данных в таблице действий.

Дальнейшие пояснения по reasonполю. Если, например, я хочу отфильтровать действия для уведомлений по электронной почте для пользователя, и пользователь добавил в закладки сообщение в блоге (и поэтому он подписывается на канал сообщений с указанием причины «закладка»), я не хочу, чтобы пользователь получал уведомления по электронной почте о действиях над этим элементом, а если он комментирует сообщение (и поэтому он подписывается на ленту сообщений с причиной «комментарий»), я хочу, чтобы он получал уведомление, когда другие пользователи добавляют комментарии к тому же сообщению. Поле причины помогает мне в этом различении (я реализовал его через класс ActivityFilter) вместе с настройками уведомлений пользователя.


Nicolo martini: я хотел добавить ответный комментарий к активности и показать его под ним, как это возможно с вашей структурой? я должен добавить еще одну таблицу или просто использовать ее, если такая же, каковы ваши предложения?
Basit

Как производительность этой реализации? Какие-нибудь тесты на больших таблицах?
Джошуа Ф. Рунтри,

16

Существует текущий формат потока активности, который разрабатывается группой хорошо известных людей.

http://activitystrea.ms/ .

По сути, у каждого действия есть субъект (который выполняет действие), глагол (действие действия), объект (на котором действует субъект) и цель.

Например: Макс разместил ссылку на стену Адама.

На момент написания их спецификация JSON достигла версии 1.0, которая показывает шаблон действия, которое вы можете применить.

Их формат уже принят BBC, Gnip, Google Buzz Gowalla, IBM, MySpace, Opera, Socialcast, Superfeedr, TypePad, Windows Live, YIID и многими другими.


привет @sntran Я знаю, что этот пост был много лет назад, но у меня есть вопрос о ленте активности. Есть ли способ помочь?
hiswendy 05

Конечно. Какой у Вас вопрос?
Sơn Trần-Nguyễn

Мой вопрос размещен здесь! ссылка . Я думаю, что у меня есть базовое представление о потоке активности, но я действительно не уверен, как его реализовать (т.е. должен ли я использовать angular или node.js?) И оттуда, как мне на самом деле СОЗДАТЬ поток активности с входящий API JSON? Это такие простые вопросы, но я не смог найти ответов в Интернете. Если вы можете помочь, я буду очень признателен. Спасибо!
hiswendy 07

13

Я думаю, что объяснение того, как работает система уведомлений на крупных веб-сайтах, можно найти в вопросе о переполнении стека, как веб-сайты социальных сетей вычисляют обновления друзей? в ответе Джереми Уолла . Он предлагает использовать Message Qeue и указывает два программного обеспечения с открытым исходным кодом, которые его реализуют:

  1. RabbitMQ
  2. Apache QPid

См. Также вопрос Как лучше всего реализовать поток социальной активности?


1

Вам абсолютно необходима эффективная и распределенная очередь сообщений. Но на этом все не заканчивается, вам придется принимать решения о том, что хранить как постоянные данные, а что как временные и т. Д.

В любом случае, мой друг, это действительно сложная задача, если вам нужна высокопроизводительная и масштабируемая система. Но, конечно, некоторые щедрые инженеры поделились своим опытом по этому поводу. LinkedIn недавно сделал свою систему очередей сообщений Kafka с открытым исходным кодом. До этого Facebook уже предоставил Scribe сообществу с открытым исходным кодом. Kafka написан на Scala, и сначала требуется некоторое время, чтобы запустить его, но я тестировал его на нескольких виртуальных серверах. Это действительно быстро.

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

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


0

Вместо того, чтобы использовать свой собственный, вы можете обратиться к стороннему сервису, используемому через API. Я начал один под названием Collabinate ( http://www.collabinate.com ), который имеет серверную часть графической базы данных и несколько довольно сложных алгоритмов для одновременной высокопроизводительной обработки больших объемов данных. Хотя у него нет такой широты функциональности, как у Facebook или Twitter, этого более чем достаточно для большинства случаев использования, когда вам нужно встроить в приложение потоки активности, социальные каналы или функции микроблогов.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.