Який найкращий спосіб здійснення потоку соціальної активності? [зачинено]


265

Мені цікаво почути вашу думку, в якому найкращий спосіб реалізувати потік соціальної активності (найвідоміший приклад Facebook). Проблеми / проблеми, пов'язані з цим:

  • Різні види діяльності (розміщення, коментування ...)
  • Різні типи об’єктів (публікація, коментар, фото ..)
  • 1-n користувачів, які беруть участь у різних ролях ("Користувач x відповів на коментар Користувача y на Z-повідомлення користувача")
  • Різні погляди на той самий предмет діяльності ("ви коментували .." проти "ваш друг x прокоментував" проти "користувач x прокоментував .." => 3 уявлення про діяльність "коментар")

.. і ще деякі, особливо якщо ви ставитеся до цього до високого рівня витонченості, як це робить, наприклад, Facebook, поєднуючи кілька предметів активності в одне ("користувачі x, y і z прокоментували цю фотографію"

Будемо вдячні будь-які думки чи вказівки щодо моделей, паперів тощо щодо найбільш гнучких, ефективних та потужних підходів до впровадження такої системи, моделі даних тощо.

Хоча більшість питань є платформово-агностичними, є ймовірність, що я закінчую впровадити таку систему на Ruby on Rails

Відповіді:


143

Я створив таку систему і взяв такий підхід:

Таблиця бази даних із такими стовпцями: id, userId, тип, дані, час.

  • userId - це користувач, який створив активність
  • тип - це тип діяльності (тобто, написав повідомлення в блозі, додану фотографію, прокоментував фотографії користувача)
  • data - це серіалізований об’єкт з метаданими для діяльності, куди ви можете вкласти все, що завгодно

Це обмежує пошукові запити / пошукові запити, які ви можете робити у каналах, для користувачів, часу та видів активності, але у стрічці активності у форматі facebook це насправді не обмежує. І при правильних показниках на столі пошуки швидко проходять .

Завдяки такому дизайну вам доведеться вирішити, які метадані потребують кожного типу подій. Наприклад, активність подачі нової фотографії може виглядати приблизно так:

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

Ви бачите, що, хоча ім’я фотографії, безумовно, зберігається в якійсь іншій таблиці, що містить фотографії, і я можу отримати ім'я звідти, я скопіюю це ім’я в полі метаданих, тому що ви цього не хочете робити будь-яке приєднання до інших таблиць баз даних, якщо ви хочете швидкості. А щоб відобразити, скажімо, 200 різних подій у 50 різних користувачів, вам потрібна швидкість.

Потім у мене є класи, які розширюють базовий клас FeedActivity для візуалізації різних типів записів діяльності. Групування подій також буде вбудовано в код візуалізації, щоб уникнути складності від бази даних.


3
Так, це правильно. Останнім часом я використовую MongoDB ( mongodb.org ) у кількох проектах, без схемний підхід яких робить дуже придатним для створення успішного потоку соціальної активності, що відповідає цьому дизайну.
Гейман

6
TheApprentice: Так, ви можете також запустити поле для імені користувача. У нашій системі ми відображали лише події, згенеровані друзями користувача, і я вважаю, що у нас вже була карта пам'яті userid-> ім'я користувача у пам'яті, тому пошук імен користувачів не потребував ПРИЄДНАЙТЕСЯ та був швидким.
Гейман

2
Вам доведеться розібратися з цією справою вручну. Мабуть, найкраще це зробити, коли фотографію буде видалено (знайдіть елемент каналу у каналі користувача та видаліть / оновіть його).
гейман

21
Я не розумію, що так чудово в цій відповіді? Як створення простої таблиці перекладається на зважену подачу діяльності, схожу на facebook? Все, що він робить, це зберігати всю активність. Що ще залишає питання про те, як перетворити таблицю даних у динамічний зважений показник активності?
ChuckKelly

4
@ChuckKelly: Якщо я пам'ятаю правильно, ще в 2008 році, коли я писав відповідь, канал у Facebook зовсім не зважувався. Це була лише хронологічна стрічка з усією діяльністю ваших друзів.
гейман

117

Це дуже гарна презентація, яка визначає, як Etsy.com архітектурував свої потоки діяльності. Це найкращий приклад, який я знайшов у цій темі, хоча це не конкретні рейки.

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


21
^^ Тому що вам потрібно повернутися до SO після відвідування сайту. lol
Стівен Корвін

1
Чудова презентація, яка докладно пояснює, як працює система на реальному веб-сайті з високим трафіком.
ramirami

44

Ми відкрили наш підхід: https://github.com/tschellenbach/Stream-Framework На даний момент це найбільша бібліотека з відкритим кодом, спрямована на вирішення цієї проблеми.

Той самий колектив, який створив Stream Framework, також пропонує розміщений API, який вирішує складність для вас. Погляньте на getstream.io Є клієнти, доступні для Node, Python, Rails та PHP.

Крім того, подивіться на цей пост із високою масштабністю, якщо ми пояснили деякі проектні рішення: http://highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your-high-traffic- feedi.html

Цей підручник допоможе вам налаштувати систему на зразок каналу Pinterest за допомогою Redis. Почати досить просто.

Щоб дізнатися більше про дизайн каналу, настійно рекомендую прочитати деякі статті, на яких ми базували Feedly:

Хоча Stream Framework базується на Python, це не буде надто складно використовувати з додатка Ruby. Ви можете просто запустити його як сервіс і вставити перед ним невеликий http API. Ми розглядаємо можливість додавання API для доступу до Feedly з інших мов. На даний момент вам доведеться зіграти свою власну.


19

Найбільші проблеми з потоками подій - це видимість та ефективність; вам потрібно обмежити відображені події лише тими, що цікавлять саме конкретного користувача, і вам потрібно зберегти кількість часу, необхідне для сортування та визначення цих подій, якими можна керувати. Я побудував невеличку соціальну мережу; Я виявив, що в невеликих масштабах зберігання таблиці "події" в базі даних працює, але це стає проблемою продуктивності при помірному навантаженні.

З більшим потоком повідомлень та користувачів, можливо, найкраще працювати з системою обміну повідомленнями, де події надсилаються у вигляді повідомлень до окремих профілів. Це означає, що ви не можете легко підписатися на потоки подій людей і переглядати попередні події дуже легко, але ви просто надаєте невелику групу повідомлень, коли вам потрібно передати потік для певного користувача.

Я вважаю, що це був оригінальний недолік дизайну Twitter - я пам'ятаю, що читав, що вони вдаряють по базі даних, щоб задіяти та фільтрувати свої події. Це мало все, що стосується архітектури, і нічого спільного з Rails, який (на жаль) породив мем "рубін не масштабує". Нещодавно я побачив презентацію, де розробник використовував службу простої черги Amazon в якості доповнення для обміну повідомленнями для програми, схожої на щебетання, який мав би набагато більші можливості масштабування - можливо, варто заглянути в SQS як частину вашої системи, якщо ваші навантаження досить високі. .


Тіме, ти випадково пам’ятаєш ім’я презентації чи презентатора?
Даніта

це було на презентації «Ігніт Бостон» у Oreilly and Associate або номер 3, або 4- я вважаю, що у ведучої була книга про масштабування RoR з Oreilly. Вибачте, я не можу бути більш конкретним!
Тім Хоуленд

Дякую Тіму :) До речі, що ти мав на увазі під "соцмережею"? Скільки користувачів або активних користувачів за певний час?
Даніта

3
Якщо комусь це потрібно, я думаю, що це презентація, про яку говорить Тім: "Ден Чак - масштабування до ваших проблем" radar.oreilly.com/2008/09/ignite-boston-4----videos -uplo.html
Даніта

Малий в цьому випадку такий, що "вибрати * з подій, де event.is видимий для цього користувача" повертає результат менше, ніж на секунду чи дві цифри, на кілька сотень тисяч рядків, вартістю кількох сотень тисяч рядків.
Тім Хоуленд

12

Якщо ви бажаєте скористатися окремим програмним забезпеченням, я пропоную сервер Graphity, який точно вирішує проблему для потоків активності (побудова на базі даних графіки neo4j).

Алгоритми реалізовані як окремий сервер REST, щоб ви могли розмістити власний сервер для доставки потоків активності: http://www.rene-pickhardt.de/graphity-server-for-social-activity-streams-released-gplv3 /

У статті та еталоні я показав, що завантаження потоків новин залежить лише лінійно від кількості елементів, які ви хочете отримати, без зайвих надмірностей, які ви отримаєте від денормалізації даних:

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

На вищенаведеному посиланні ви знайдете скріншоти та орієнтир такого підходу (показуючи, що графічність здатна отримати більше 10 К потоків в секунду).


10

Я вчора почав реалізовувати таку систему, ось де мені доводиться ...

Я створив клас StreamEvent із властивостями Id , ActorId , TypeId , Date , ObjectId та хештелем додаткових пар деталей ключ / значення. Це представлено в базі даних з допомогою StreamEvent таблиці ( Id , ActorId , TypeId , Дата , ObjectId ) і StreamEventDetails таблиці ( StreamEventId , DetailKey , DetailValue ).

ActorId , TypeId і ObjectId дозволяють подія Тема-Дієслово-Об'єкт , який повинен бути захоплений (а потім опитано). Кожна дія може призвести до створення декількох екземплярів StreamEvent.

Потім я створив підклас для StreamEvent для кожного типу подій, наприклад, LoginEvent , PictureCommentEvent . Кожен з цих підкласів має більше контексту конкретні властивості , такі як PictureId , мініатюру , , CommenText , і т.д. (все , що потрібно для події) , які на насправді зберігаються в вигляді пар ключ / значення в хеш - таблиці / StreamEventDetail.

Коли витягую ці події назад із бази даних, я використовую заводський метод (заснований на TypeId ) для створення правильного класу StreamEvent.

Кожен підклас StreamEvent має метод Render ( контекст як StreamContext ), який виводить подію на екран на основі пройденого класу StreamContext . Клас StreamContext дозволяє встановлювати параметри залежно від контексту подання. Якщо ви, наприклад, переглядаєте Facebook, у вашій стрічці новин на домашній сторінці вказуються повні імена (та посилання на їх профіль) усіх, хто бере участь у кожній дії, тоді як дивлячись стрічку друга, ви бачите лише їх ім’я (але повні імена інших акторів) .

Я ще не застосував сукупний канал (домашня сторінка Facebook), але я думаю, що буду створити таблицю AggregateFeed, у якій поля поля UserId , StreamEventId , заповнені на основі якогось алгоритму "Хммм, ви можете знайти цей цікавий" алгоритм.

Будь-які коментарі були б вдячні.


Я працюю над такою системою, мене дуже цікавлять будь-які знання про неї, ви коли-небудь закінчували свою?
JasonDavis

Чудова відповідь! Відмінне розділення турбот, чисто та елегантно!
Мош

Це вдалий старт! Це дуже схоже на те, як я почав реалізовувати свій перший потік. Однак, як тільки ви перейдете до сукупного каналу, все починає швидко ускладнюватися. Ви праві, що вам потрібен надійний алгоритм. Мій пошук привів мене до алгоритму Рене Пікхардта (він розповідає про це у своїй відповіді тут), який я потім реалізував у власному сервісі, котрий зараз є комерційним (детальніше дивіться kolabinate.com та мою відповідь на це питання).
Мафуба

10
// один запис на фактичну подію
події {
  id, часова марка, тип, дані
}

// один запис на подію, на канал, що містить цю подію
events_feeds {
  event_id, feed_id
}

Коли подія створена, вирішіть, у яких каналах вона відображається, і додайте їх до подій_файлів. Щоб отримати канал, виберіть із подій_файлів, приєднайтесь до подій, замовляйте за часовою позначкою. Після цього можна виконати фільтрацію та агрегацію за результатами цього запиту. За допомогою цієї моделі ви можете змінювати властивості події після створення без зайвих робіт.


1
Припустимо, що хтось ще додається як друг після події, якій потрібно бачити цю подію у стрічці? тоді це не вийде
Джошуа Кіссон

8

Якщо ви все-таки вирішите, що збираєтесь реалізувати в Rails, можливо, вам буде корисний наступний плагін:

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

Якщо нічого іншого, ви подивитеся на реалізацію, як з точки зору моделі даних, так і API, що надається для натискань та витягувань.


6

У мене був аналогічний підхід до гейману - денормалізованої таблиці, що містить усі дані, які відображатимуться в потоці потоку діяльності. Це чудово працює для невеликого сайту з обмеженою активністю.

Як було сказано вище, під час зростання сайту, ймовірно, виникнуть проблеми зі масштабуванням. Особисто я зараз не переживаю проблем масштабування. Я буду хвилюватися про це згодом.

Facebook, очевидно, зробив велику роботу з масштабування, тому я рекомендую вам прочитати їхній інженерний блог, оскільки він має великий вміст -> http://www.facebook.com/notes.php?id=9445547199

Я розглядав кращі рішення, ніж денормалізована таблиця, про яку я згадував вище. Ще один спосіб, який я знайшов досягти цього, - це конденсувати весь вміст, який знаходився б у потоці потоку діяльності, в один ряд. Він може бути збережений у XML, JSON або в деякому серіалізованому форматі, який можна прочитати у вашій програмі. Процес оновлення теж був би простим. Після активності розмістіть нову активність у черзі (можливо, використовуючи Amazon SQS або щось інше), а потім постійно запитуйте чергу для наступного елемента. Візьміть цей елемент, проаналізуйте його та розмістіть його вміст у відповідному об’єкті каналу, що зберігається в базі даних.

Хороша річ у цьому методі полягає в тому, що вам потрібно читати єдину таблицю бази даних кожного разу, коли вимагається конкретний канал, а не захоплювати ряд таблиць. Крім того, це дозволяє підтримувати кінцевий список видів діяльності, оскільки ви можете вискакувати найстаріший елемент діяльності щоразу, коли ви оновите список.

Сподіваюсь, це допомагає! :)


Саме мої думки, мені просто потрібна була перевірка моїх думок, які я, мабуть, отримав зараз, ура!
Sohail

5

Про такий потік діяльності існує два рейлові трансляції:

Ці рішення не містять усіх ваших вимог, але вони повинні дати вам кілька ідей.


1
PublicActivity є чудовим і може вирішувати всі випадки використання у питанні.
DaveStephens

3

Я думаю , що підхід Плурка цікавий: вони надають всю вашу часову шкалу у форматі, який дуже схожий на акціонерні графіки Google Finance.

Можливо, варто поглянути на Нін, щоб побачити, як працює мережа соціальних мереж. У девелоперський сторінках виглядають особливо корисні.


2

Я вирішив це кілька місяців тому, але вважаю, що моя реалізація є занадто базовою.
Я створив такі моделі:

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

Приклад

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

2

Після впровадження потоків активності для включення функцій соціальних каналів, мікроблогів та співпраці в декількох додатках я зрозумів, що базовий функціонал є досить поширеним і може бути перетворений на зовнішню службу, яку ви використовуєте за допомогою API. Якщо ви будуєте потік у виробничому додатку і не маєте унікальних або глибоко складних потреб, використання перевіреної послуги може бути найкращим способом. Я б точно рекомендував це для виробничих застосувань для прокатки власного простого рішення поверх реляційної бази даних.

Моя компанія Collabinate ( http://www.collabinate.com ) виросла з цієї реалізації, і ми реалізували масштабований, високоефективний потіковий механізм активності над графічною базою даних, щоб досягти цього. Ми фактично використали варіант алгоритму Graphity (адаптований на початку роботи @RenePickhardt, який також дав відповідь тут) для створення двигуна.

Якщо ви хочете влаштувати двигун самостійно або вам потрібна спеціалізована функціональність, основний код насправді є відкритим кодом для некомерційних цілей, тому ви можете ознайомитися.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.