소셜 활동 스트림을 구현하는 가장 좋은 방법은 무엇입니까? [닫은]


265

소셜 활동 스트림을 구현하는 가장 좋은 방법 인 귀하의 의견을 듣고 싶습니다 (Facebook이 가장 유명한 예입니다). 관련된 문제 / 도전은 다음과 같습니다.

  • 다양한 유형의 활동 (게시, 댓글 작성 ..)
  • 다양한 유형의 객체 (게시물, 댓글, 사진 ..)
  • 다른 역할에 관련된 1-n 명의 사용자 ( "사용자 x는 사용자의 Z 게시물에 대한 사용자 y의 의견에 답변했습니다")
  • 동일한 활동 항목의 다른보기 ( "댓글을 달았습니다 .."vs. "친구 x는 댓글을 달았습니다"vs. "사용자 x는 댓글을 달았습니다 .."=> "댓글"활동의 3 가지 표현)

예를 들어 Facebook이 여러 활동 항목을 하나로 결합 (예 : 사용자 x, y 및 z가 해당 사진에 댓글을 달았습니다)

그러한 시스템, 데이터 모델 등을 구현하기위한 가장 유연하고 효율적이며 강력한 접근 방식에 대한 패턴, 논문 등에 대한 생각이나 포인터는 높이 평가 될 것입니다.

대부분의 문제는 플랫폼에 구애받지 않지만 Ruby on Rails에서 이러한 시스템을 구현할 가능성이 있습니다.

답변:


143

나는 그러한 시스템을 만들었고이 접근법을 취했습니다.

id, userId, type, data, time 열이있는 데이터베이스 테이블

  • userId 는 활동을 생성 한 사용자입니다.
  • type 은 활동의 유형입니다 (예 : 블로그 게시물 작성, 사진 추가, 사용자 사진에 댓글 추가)
  • data 는 원하는 것을 넣을 수있는 활동에 대한 메타 데이터 가있는 직렬화 된 객체입니다.

이렇게하면 피드, 사용자, 시간 및 활동 유형에 대한 검색 / 조회가 제한되지만 페이스 북 유형 활동 피드에서는 제한되지 않습니다. 그리고 테이블에 정확한 인덱스가 있으면 조회가 빠릅니다. .

이 디자인을 사용하면 각 이벤트 유형에 필요한 메타 데이터를 결정해야합니다. 예를 들어 새 사진의 피드 활동은 다음과 같습니다.

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

사진의 이름이 사진을 포함하는 다른 테이블에 가장 확실하게 저장되어 있지만 거기에서 이름을 검색 할 수 있지만 메타 데이터 필드에 이름을 복제합니다. 속도를 원하는 경우 다른 데이터베이스 테이블의 조인 그리고 50 명의 다른 사용자로부터 200 개의 다른 이벤트를 표시하려면 속도가 필요합니다.

그런 다음 다양한 유형의 활동 항목을 렌더링하기 위해 기본 FeedActivity 클래스를 확장하는 클래스가 있습니다. 렌더링 코드에는 이벤트 그룹화가 내장되어 데이터베이스와의 복잡성을 방지합니다.


3
네 맞습니다. 최근에 나는 몇 가지 프로젝트에서 MongoDB ( mongodb.org )를 사용해 왔으며 스키마없는 접근 방식 으로이 디자인을 따르는 우수한 사회 활동 스트림을 만드는 데 매우 적합합니다.
heyman

6
The 견습생 : 그렇습니다, 당신은 또한 사용자 이름 필드에 던지기를 원할 것입니다. 우리 시스템에서는 사용자의 친구가 생성 한 이벤트 만 표시했으며 메모리에 친구의 사용자 아이디-> 사용자 이름 맵이 이미 있다고 생각하므로 사용자 이름을 찾는 데 JOIN이 필요없고 빠릅니다.
heyman

2
이 경우를 수동으로 처리해야합니다. 사진이 삭제 될 때 수행하는 것이 가장 좋습니다 (사용자 피드에서 피드 항목을 찾아 삭제 / 업데이트).
heyman

21
나는이 답변에 대해 무엇이 그렇게 큰지 이해하지 못합니까? 간단한 테이블을 작성하면 페이스 북과 유사한 가중치 활동 피드로 어떻게 변환됩니까? 그가하는 모든 일은 모든 활동을 저장하는 것입니다. 데이터 테이블을 동적 가중치 활동 피드로 바꾸는 방법에 대한 의문은 여전히 ​​남아 있습니까?
ChuckKelly

4
@ChuckKelly : 2008 년에 답을 썼을 때 정확하게 기억한다면 페이스 북 피드는 전혀 가중치가 없었습니다. 친구의 모든 활동을 시간순으로 표시 한 것입니다.
heyman

117

이것은 Etsy.com이 활동 스트림을 어떻게 설계했는지를 설명하는 매우 훌륭한 프레젠테이션입니다. 난간에 관한 것이 아니지만 주제에서 찾은 가장 좋은 예입니다.

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


21
^^ 사이트를 방문한 후 SO로 돌아와야하기 때문입니다. lol
Stephen Corwin

1
트래픽이 많은 실제 웹 사이트에서 시스템이 작동하는 방식을 자세히 설명하는 훌륭한 프레젠테이션.
ramirami

44

우리는 열려있는 우리의 접근을 공급했습니다 https://github.com/tschellenbach/Stream-Framework 그것은 현재이 문제를 해결하기위한 가장 큰 오픈 소스 라이브러리입니다.

Stream Framework를 구축 한 팀도 복잡성을 처리하는 호스팅 된 API를 제공합니다. getstream.io를 살펴보십시오. Node, Python, Rails 및 PHP에 사용 가능한 클라이언트가 있습니다.

또한이 높은 확장 성 게시물을 살펴보면 관련된 디자인 결정 중 일부를 설명했습니다 . feeds.html

이 튜토리얼 은 Redis를 사용하여 Pinterest의 피드와 같은 시스템을 설정하는 데 도움이됩니다. 시작하기가 매우 쉽습니다.

피드 디자인에 대해 자세히 알아 보려면 Feedly를 기반으로하는 기사 중 일부를 읽는 것이 좋습니다.

Stream Framework는 Python 기반이지만 Ruby 앱에서는 사용하기가 어렵지 않습니다. 간단히 서비스로 실행하고 앞에 작은 http API를 붙일 수 있습니다. 다른 언어에서 Feedly에 액세스하기위한 API 추가를 고려하고 있습니다. 현재로서는 자신의 역할을 맡아야합니다.


19

이벤트 스트림의 가장 큰 문제는 가시성과 성능입니다. 표시되는 이벤트를 해당 특정 사용자에게 흥미로운 이벤트로 제한해야하며 해당 이벤트를 정렬하고 식별하는 데 걸리는 시간을 유지해야합니다. 나는 작은 소셜 네트워크를 구축했습니다. 소규모로, 데이터베이스에 "이벤트"테이블을 유지하면 작동하지만 중간 정도의로드에서는 성능 문제가된다는 것을 알았습니다.

더 많은 메시지 및 사용자 스트림을 사용하는 경우 이벤트가 개별 프로파일에 메시지로 전송되는 메시징 시스템을 사용하는 것이 가장 좋습니다. 즉, 사람들의 이벤트 스트림을 쉽게 구독 할 수없고 이전 이벤트를 매우 쉽게 볼 수 있지만 특정 사용자에 대한 스트림을 렌더링해야 할 때 작은 메시지 그룹을 렌더링하는 것입니다.

나는 이것이 트위터의 독창적 인 디자인 결함이라고 생각한다. 나는 그들이 이벤트를 가져 와서 필터링하기 위해 데이터베이스를 쳤다는 것을 기억한다. 이것은 아키텍처와 관련이 있고 Rails와는 아무런 관련이 없었습니다. 불행히도 "루비는 확장 할 수 없습니다"밈을 낳았습니다. 필자는 최근 개발자가 Amazon의 Simple Queue Service 를 훨씬 높은 확장 기능을 가진 트위터와 같은 애플리케이션의 메시징 백엔드로 사용한 프레젠테이션을 보았습니다. 부하가 충분히 높은 경우 시스템의 일부로 SQS를 살펴볼 가치가 있습니다. .


팀, 프리젠 테이션이나 발표자의 이름을 기억하십니까?
Danita

그것은 Oreilly와 Associate의 Ignite Boston 프레젠테이션에서 3 번이나 4 번에있었습니다. 발표자는 Oreilly와 함께 RoR을 확장하는 것에 관한 책을 가지고 있다고 생각합니다. 더 구체적으로 말씀 드릴 수 없습니다!
Tim Howland

감사합니다 Tim :) 그런데 "작은 소셜 네트워크"란 무슨 뜻입니까? 특정 시간에 몇 명의 사용자 또는 활성 사용자입니까?
Danita

3
누군가가 필요로한다면, 이것은 Tim이 말하고있는 프레젠테이션이라고 생각합니다. "Dan Chak-
Danita

이 경우 "이벤트 *이 사용자에게 표시되는 이벤트에서 select *"가 수십만 행에 달하는 이벤트의 수를 2 초에서 2 초 미만으로 반환하도록 작습니다.
Tim Howland

12

별도의 소프트웨어를 사용하려는 경우 활동 스트림 (neo4j 그래프 데이터베이스 기반으로 구축)의 문제를 정확하게 해결하는 Graphity 서버를 제안합니다.

알고리즘은 독립형 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/

위의 링크에서 스크린 캐스트와이 방법의 벤치 마크를 볼 수 있습니다 (그래프 티가 초당 10k 개 이상의 스트림을 검색 할 수 있음을 보여줍니다).


10

어제 이와 같은 시스템을 구현하기 시작했습니다.

Id , ActorId , TypeId , Date , ObjectId 속성 과 추가 Details 키 / 값 쌍 의 해시 테이블을 사용 하여 StreamEvent 클래스를 만들었습니다 . 이것은 데이터베이스에서 StreamEvent 테이블 ( Id , ActorId , TypeId , Date , ObjectId ) 및 StreamEventDetails 테이블 ( StreamEventId , DetailKey , DetailValue )로 표시됩니다.

ActorId , 유형 ID ObjectId가 주체 - 동사 - 개체 이벤트가 캡처 (나중에 쿼리) 할 수 있도록. 각 작업으로 인해 여러 개의 StreamEvent 인스턴스가 생성 될 수 있습니다.

그런 다음 각 유형의 이벤트 (예 : LoginEvent , PictureCommentEvent)에 대한 StreamEvent의 하위 클래스를 작성했습니다 . 이러한 각 서브 클래스에는 PictureId , ThumbNail , CommenText 와 같은 컨텍스트 별 특성이 있습니다. 실제로 해시 테이블 / StreamEventDetail 테이블에 키 / 값 쌍으로 저장되는 (이벤트에 필요한 것)이 있습니다.

데이터베이스에서 이러한 이벤트를 다시 가져올 때 팩토리 메소드를 사용합니다 ( TypeId 기반). 가져올 )를 사용하여 올바른 StreamEvent 클래스를 작성합니다.

StreamEvent의 각 하위 클래스 에는 전달 된 StreamContext를 기반으로 이벤트를 화면에 출력 하는 Render ( context As StreamContext ) 메서드가 있습니다. 클래스를 있습니다. StreamContext 클래스를 사용하면 뷰의 컨텍스트에 따라 옵션을 설정할 수 있습니다. 예를 들어 Facebook을 보면 홈페이지의 뉴스 피드에 각 작업에 관련된 모든 사람의 이름과 프로필 링크가 나열되어 있지만 친구의 피드를 보면 이름 만 볼 수 있지만 다른 배우의 이름 만 볼 수 있습니다. .

아직 집계 피드 (Facebook 홈)를 구현하지 않았지만 UserId , StreamEventId 필드가 있는 AggregateFeed 테이블을 생성한다고 가정 합니다. 일종의 'Hmmm, 당신은이 흥미로운 것을 찾을 수 있습니다'알고리즘을 합니다.

모든 의견은 대단히 감사하겠습니다.


나는 이와 같은 시스템에서 일하고 있으며 그것에 대한 지식에 매우 관심이 있습니다.
JasonDavis

좋은 답변입니다! 깨끗하고 우아한 우려의 뛰어난 분리!
Mosh

이것은 좋은 시작입니다! 첫 스트림 구현을 시작한 방법과 매우 유사합니다. 그러나 집계 피드에 도달하면 상황이 빠르게 복잡해지기 시작합니다. 강력한 알고리즘이 필요합니다. 내 검색을 통해 Rene Pickhardt의 알고리즘 (그의 답변에서 그것에 대해 이야기 함)으로 이동하여 현재 상용 서비스로 구현했습니다 ( collabinate.com 및 자세한 내용은이 질문에 대한 답변 참조).
Mafuba

10
// 실제 이벤트 당 하나의 항목
이벤트 {
  ID, 타임 스탬프, 유형, 데이터
}

// 이벤트 당 하나의 항목, 해당 이벤트를 포함하는 피드 당
events_feeds {
  event_id, feed_id
}

이벤트가 작성되면 표시되는 피드를 결정하고 events_feeds에 추가하십시오. 피드를 받으려면 events_feeds에서 선택하고 이벤트에 참여하며 타임 스탬프별로 정렬하십시오. 그런 다음 해당 쿼리 결과에서 필터링 및 집계를 수행 할 수 있습니다. 이 모델을 사용하면 추가 작업없이 작성 후 이벤트 특성을 변경할 수 있습니다.


1
이벤트가 추가 된 후 다른 사람이 친구로 추가되었다고 가정하면 피드에서이 이벤트를보아야합니까? 다음이 작동하지 않을 것입니다
여호수아 Kissoon에게


6

특정 활동 스트림에 표시 될 모든 데이터를 포함하는 비정규 화 된 테이블 인 heyman과 비슷한 접근 방식을 가졌습니다. 활동이 제한된 소규모 사이트에 적합합니다.

위에서 언급했듯이 사이트가 성장함에 따라 확장 성 문제에 직면 할 수 있습니다. 개인적으로 현재 스케일링 문제에 대해 걱정하지 않습니다. 나중에 그것에 대해 걱정할 것입니다.

페이스 북은 분명히 훌륭한 스케일링 작업을 수행 했으므로 엔지니어링 블로그에 엄청난 양의 컨텐츠가 포함되어 있기 때문에 엔지니어링 블로그를 읽는 것이 좋습니다.-> http://www.facebook.com/notes.php?id=9445547199

위에서 언급 한 비정규 화 된 테이블보다 더 나은 솔루션을 찾고 있습니다. 내가 이것을 달성하는 또 다른 방법은 주어진 활동 스트림에있을 모든 내용을 단일 행으로 요약하는 것입니다. XML, JSON 또는 응용 프로그램에서 읽을 수있는 직렬화 된 형식으로 저장 될 수 있습니다. 업데이트 프로세스도 간단합니다. 활동이 발생하면 새 활동을 대기열에 넣고 (아마도 Amazon SQS 등을 사용하여) 다음 항목의 대기열을 계속 폴링합니다. 해당 항목을 잡고 구문 분석 한 후 해당 컨텐츠를 데이터베이스에 저장된 적절한 피드 오브젝트에 배치하십시오.

이 방법의 좋은 점은 일련의 테이블을 가져 가지 않고 특정 피드가 요청 될 때마다 단일 데이터베이스 테이블 만 읽으면된다는 것입니다. 또한 목록을 업데이트 할 때마다 가장 오래된 활동 항목이 나타날 수 있으므로 유한 활동 목록을 유지할 수 있습니다.

도움이 되었기를 바랍니다! :)


정확히 내 생각, 방금 내가 생각했던 내 생각에 대한 검증이 필요했습니다.
Sohail

5

이러한 활동 스트림에 대한 두 가지 레일 캐스트가 있습니다.

이러한 솔루션에는 모든 요구 사항이 포함되어 있지는 않지만 몇 가지 아이디어를 제공해야합니다.


1
PublicActivity는 훌륭하며 질문의 모든 사용 사례를 처리 할 수 ​​있습니다.
DaveStephens

3

내 생각 소리 접촉의 접근 방식은 흥미 롭다 : 그들은 Google 금융의 주식 차트처럼 많이 보이는 형식으로 전체 타임 라인을 제공합니다.

소셜 네트워킹 네트워크의 작동 방식을 확인하려면 Ning 을 살펴볼 가치가 있습니다 . 개발자 페이지는 특히 도움이 보인다.


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의 초기 작업에서 수정)을 사용했습니다.

엔진을 직접 호스팅하거나 특수 기능이 필요한 경우 핵심 코드는 실제로 비상업적 목적을위한 오픈 소스이므로 살펴볼 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.