Вопрос

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

Это было полезно?

Решение

Краткие сведения:Примерно для 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 хранит все свои данные в памяти, поэтому вы не можете поместить туда все свои действия, но вы могли бы сохранить достаточно для большинства часто посещаемых экранов вашего сайта.Самые последние 100 для каждого пользователя или что-то в этом роде.С Redis в сочетании это может работать следующим образом:

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

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

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

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

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

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

Другие советы

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

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

id
subject_id
object_id
type
verb
data
time

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

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

feed_name
activity_id

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

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

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

feed_name
subscriber_id
reason

Поле reason объясняет, почему подписчик подписался на канал. Например, если пользователь делает закладку на запись в блоге, причина - «закладка». Это поможет мне позже в фильтрации действий для уведомлений пользователей.

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

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

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

http://activitystrea.ms/ .

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

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

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

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

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

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

http://blog.linkedin.com/2011 / 01/11 / с открытым исходным-LinkedIn-Кафка /

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top