SlideShare a Scribd company logo
Content Recommendation

(Item-Item Collaborative Filtering)
In Serverless
Kurt Lee
Technical Leader, Vingle Inc
iOS / Frontend / Backend
kurt@vingle.net
https://github.com/breath103
목표: 

“사용자의 반응에 기반하여,

새로운 컨텐츠 추천”
1. Item-Item Collaborative Filtering
2. Serverless Data Pipeline for CF
Collaborative Filtering
A가 B를 샀다
B를 사면 C도 산다
A는 C를 살 것이다.
A. User-Item Approach
B. Item-Item Approach
SageMaker / Tensorflow 등으로 가능
S3 + Athena 등으로 가능
A. User-Item Approach
Assume)

Rating(U, I) = UserFeatures[U] * ItemFeatures[I]
SageMaker Factorization Machine

(https://docs.aws.amazon.com/sagemaker/latest/dg/fact-machines.html)
Spark ML

(EMR)
Collborative Filtering

(https://spark.apache.org/docs/latest/ml-collaborative-filtering.html)
A. User-Item Approach
1) it requires training
2) it requires massive data to store

User * Features + Item * Features
3) it gets really expensive when it get’s big

O(user * item)
B. Item-Item Approach
User의 ItemA에 대한 예상 점수
= AVG(User가 이미 평가한 ItemB의 점수 * ItemB와 ItemA의 유사도 점수)
User의 ItemA에 대한 예상 점수 ( “Like” 만 있을때 )
= AVG(User가 좋아한 ItemB와 ItemA의 유사도 점수)
내가 A, B를 Like했고, S(A, C) = 0.5, S(B, C) = 0.8 이면,

나의 C에 대한 예상 점수 = (0.5 + 0.8) / 2 = 0.65
장점
1)User-Item Rating, Item-Item Similarity 두개만 관리하면되서,
사이즈가 훨씬 작음.

(특히, Item 갯수가 User 갯수에 비해 작을땐)

2)자연스럽게 Item-Item Similarity를 알게 되기 때문에, 

"요 Item의 Related Items..." 를 일석이조
주어진 아이템 A, B의 “유사성”은 

어떻게 점수화?
Jaccard Index
다양한 변형 (Tanimoto, Sigmoid, …) 이 있지만, 

공통적인 가장 중요한 특성은,
A = A를 좋아한 사람 숫자
B = B를 좋아한 사람 숫자
A ⋂ B = A와 B를 모두 좋아한 사람 숫자
ex)
참고: 여러가지 Jaccard Similarity Function을 비교해 봤는데, 

Sigmoid Jaccard가 가장 퍼포먼스 좋았습니다.
http://www.semantic-web-journal.net/system/files/swj1740.pdf
Application
Interest Recommendation
데이터 수집
{

content_id: string,
user_id: number,
at: timestamp
}
데이터 수집이 잘 되어있다는 가정하에…
1) Item-Item Jaccard Score를 Athena에서 계산해서, 

Aurora로 "LOAD FROM"

2) User-Item을 Athena에서 정리하여, 

Aurora로 "LOAD FROM"

3) Lambda에서, UserId로 두 table을 조회하여 계산
빠르게 접근 가능해야 하는 데이터
1) Interest - Interest 연관도

Array<{ A, B, Score (0~1) }>
2) “내가” 최근에 좋아한 Interest 목록

Array<{ user, interest }>
Interest-Interest score
A = A를 방문한 사람
B = B를 방문한 사람
A ⋂ B = A와 B를 모두 방문한 사람
Interest-Interest score
WITH
interest_reads AS (
SELECT
user_id,
content_id as interest
FROM user_actions
WHERE
(year || month || day) >
date_format(CURRENT_TIMESTAMP - interval '30' DAY, '%Y%m%d')
GROUP BY 1, 2
),
ab_inner_reads_count AS (
SELECT
a.interest AS a,
b.interest AS b,
count(1) AS count
FROM interest_reads a
JOIN interest_reads b ON a.user_id = b.user_id AND a.interest < b.interest
GROUP BY 1, 2
),
reads_count AS (
SELECT
interest, count(1) AS count
FROM interest_reads
GROUP BY 1
),
similarity AS (
SELECT
innerCnt.a AS a,
innerCnt.b AS b,
(innerCnt.count / (aCount.count + bCount.count - innerCnt.count)) AS score
FROM ab_inner_reads_count AS innerCnt
JOIN reads_count AS aCount ON aCount.interest = innerCnt.a
JOIN reads_count AS bCount ON bCount.interest = innerCnt.b
)
SELECT * FROM similarity
[user_id, interest]
[A, count]
[A, B, count]

To avoid [B, A, count], a < b
[A, B, count] JOIN [A, count] JOIN [B, count]
[A, B, score]
Record가 너무 많음.

Item이 n개일때, n*n 개...
30000 => 900,000,000
S3에는 문제 없지만, 

Aurora에 넣으면 너무 비쌈
[A, B, 0.5]
[A, C, 0.3]
[A, D, 0.2]
[A, "(B, 0.5), (C, 0.3), (D, 0.2)"]
ARRAY_AGG!
(year || month || day) >
date_format(CURRENT_TIMESTAMP - interval '30' DAY, '%Y%m%d')
GROUP BY 1, 2
),
ab_inner_reads_count AS (
SELECT
a.interest AS a,
b.interest AS b,
count(1) AS count
FROM interest_reads a
JOIN interest_reads b ON a.user_id = b.user_id AND a.interest < b.interest
GROUP BY 1, 2
),
reads_count AS (
SELECT
interest, count(1) AS count
FROM interest_reads
GROUP BY 1
),
similarity AS (
SELECT
innerCnt.a AS a,
innerCnt.b AS b,
(innerCnt.count / (aCount.count + bCount.count - innerCnt.count)) AS score
FROM ab_inner_reads_count AS innerCnt
JOIN reads_count AS aCount ON aCount.interest = innerCnt.a
JOIN reads_count AS bCount ON bCount.interest = innerCnt.b
)
SELECT
a, 

json_format(
CAST(
array_agg(
ROW(b, score)
) AS JSON
)
) as cards
FROM similarity
GROUP BY 1
[A, "[[B, 0.1], [C, 0.2]....]"]

[B, "[[C, 0.1], [D, 0.2]....]"]
LOAD DATA FROM S3 's3://vingle-redshift/athena_output.csv'
REPLACE
INTO TABLE interest_similarity
CHARACTER SET 'utf8mb4'
FIELDS
TERMINATED BY ','
ENCLOSED BY '"'
IGNORE 1 ROWS (@interest, @others)
SET
interest = @interest,
others = @others,
created_at = CURRENT_TIMESTAMP;
CREATE TABLE `interest_similarity` (
`interest` VARCHAR(50) NOT NULL,
`others` text COLLATE utf8mb4_bin NOT NULL,
`created_at` datetime NOT NULL,
PRIMARY KEY (`interest`)
)
Aurora로 Load!
User-Recently-Visited-Interest
Record가 너무 많음.
유저가 평균 100개 본다 => User * 100
User-Recently-Visited-Interest
WITH
interest_reads AS (
SELECT
session_data.user_id,
data.content.id as interest
FROM track_tickets.user_content_action
WHERE
(year || month || day) > date_format(CURRENT_TIMESTAMP - interval '30' DAY, '%Y%m%d')
GROUP BY
1, 2
)
SELECT
user_id,
json_format(CAST(array_agg(ROW(interest)) AS JSON)) as interests
FROM interest_reads
GROUP BY 1
[user_id, "[['A'], ['B'], ....]"]
LOAD DATA FROM S3 's3://vingle-redshift/athena_output.csv'
REPLACE
INTO TABLE user_interest
CHARACTER SET 'utf8mb4'
FIELDS
TERMINATED BY ','
ENCLOSED BY '"'
IGNORE 1 ROWS (@user_id, @others)
SET
user_id = @user_id,
others = @others,
created_at = CURRENT_TIMESTAMP;
CREATE TABLE `user_interest` (
`user_id` INT NOT NULL,
`others` text COLLATE utf8mb4_bin NOT NULL,
`created_at` datetime NOT NULL,
PRIMARY KEY (`user_id`)
)
Aurora로 Load!
Done! Let's Query
async function recommendedInterests(userId: number) {
const visitedInterests = JSON.parse(
(await UserVisitedInterests.find(userId)).others
) as Array<string>;
// [interest, "[[A, score], [B, score]]"]...
const related = await InterestInterestSimilarity.findAll({ interest: visitedInterests });
return _.chain(visitedInterests)
.flatMap((base) => {
const similarItems = related.find(i => i.interest === base);
// How much user likes interest. 1 for every interests now
return (
JSON.parse(similarItems.others) as Array<[string, number]>
).map(item => {
return {
interest: item[0],
score: item[1] * (1.0) /** base.score */,
};
});
})
.groupBy(i => i.interest)
.mapValues(items =>
_.chain(items).map(i => i.score).sum().value() / items.length
)
.sortBy(i => - i.score)
.value();
}
정리)
S3 + Athena + Aurora 조합
무거운 쿼리는 Athena로, 빠른 Access가 필요한 결과물은Aurora로
데이터 수집은 Firehose + S3로
+ 진리의 JSON
Athena도 API로, Cron
Cloudwatch Cron => Lambda => Athena => Aurora
QnA

More Related Content

Similar to Serverless content recommendation

Mongo db 최범균
Mongo db 최범균Mongo db 최범균
Mongo db 최범균
beom kyun choi
 
Amazon Machine Learning 게임에서 활용해보기 :: 김일호 :: AWS Summit Seoul 2016
Amazon Machine Learning 게임에서 활용해보기 :: 김일호 :: AWS Summit Seoul 2016Amazon Machine Learning 게임에서 활용해보기 :: 김일호 :: AWS Summit Seoul 2016
Amazon Machine Learning 게임에서 활용해보기 :: 김일호 :: AWS Summit Seoul 2016
Amazon Web Services Korea
 
R 프로그램의 이해와 활용 v1.1
R 프로그램의 이해와 활용 v1.1R 프로그램의 이해와 활용 v1.1
R 프로그램의 이해와 활용 v1.1
happychallenge
 
Logstash, ElasticSearch, Kibana
Logstash, ElasticSearch, KibanaLogstash, ElasticSearch, Kibana
Logstash, ElasticSearch, Kibana
HyeonSeok Choi
 
[1A5]효율적인안드로이드앱개발
[1A5]효율적인안드로이드앱개발[1A5]효율적인안드로이드앱개발
[1A5]효율적인안드로이드앱개발
NAVER D2
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8Sangmin Lee
 
배워봅시다 머신러닝 with TensorFlow
배워봅시다 머신러닝 with TensorFlow배워봅시다 머신러닝 with TensorFlow
배워봅시다 머신러닝 with TensorFlow
Jang Hoon
 
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
Seok-joon Yun
 
StarUML NS Guide - Design
StarUML NS Guide - DesignStarUML NS Guide - Design
StarUML NS Guide - Design
태욱 양
 
집단지성 프로그래밍 03-군집발견-03
집단지성 프로그래밍 03-군집발견-03집단지성 프로그래밍 03-군집발견-03
집단지성 프로그래밍 03-군집발견-03
Kwang Woo NAM
 
Python machine learning Ch.4
Python machine learning Ch.4Python machine learning Ch.4
Python machine learning Ch.4
PartPrime
 
Software Development Process - Korean
Software Development Process - KoreanSoftware Development Process - Korean
Software Development Process - Korean
Terry Cho
 
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613KTH, 케이티하이텔
 
Django를 Django답게, Django로 뉴스 사이트 만들기
Django를 Django답게, Django로 뉴스 사이트 만들기Django를 Django답게, Django로 뉴스 사이트 만들기
Django를 Django답게, Django로 뉴스 사이트 만들기
Kyoung Up Jung
 
KCSE 2015 Tutorial 빅데이터 분석 기술의 소프트웨어 공학 분야 활용 (...
KCSE 2015 Tutorial 빅데이터 분석 기술의  소프트웨어 공학 분야 활용 (...KCSE 2015 Tutorial 빅데이터 분석 기술의  소프트웨어 공학 분야 활용 (...
KCSE 2015 Tutorial 빅데이터 분석 기술의 소프트웨어 공학 분야 활용 (...
Chanjin Park
 
2017 AWS DB Day | 개발자가 알아야 할 Amazon DynamoDB 활용법
2017 AWS DB Day | 개발자가 알아야 할 Amazon DynamoDB 활용법 2017 AWS DB Day | 개발자가 알아야 할 Amazon DynamoDB 활용법
2017 AWS DB Day | 개발자가 알아야 할 Amazon DynamoDB 활용법
Amazon Web Services Korea
 
Python 활용: 이미지 처리와 데이터 분석
Python 활용: 이미지 처리와 데이터 분석Python 활용: 이미지 처리와 데이터 분석
Python 활용: 이미지 처리와 데이터 분석
용 최
 
Ots2014 arcus-collection-open source
Ots2014 arcus-collection-open sourceOts2014 arcus-collection-open source
Ots2014 arcus-collection-open sourceNAVER D2
 

Similar to Serverless content recommendation (20)

Mongo db 최범균
Mongo db 최범균Mongo db 최범균
Mongo db 최범균
 
Amazon Machine Learning 게임에서 활용해보기 :: 김일호 :: AWS Summit Seoul 2016
Amazon Machine Learning 게임에서 활용해보기 :: 김일호 :: AWS Summit Seoul 2016Amazon Machine Learning 게임에서 활용해보기 :: 김일호 :: AWS Summit Seoul 2016
Amazon Machine Learning 게임에서 활용해보기 :: 김일호 :: AWS Summit Seoul 2016
 
R 프로그램의 이해와 활용 v1.1
R 프로그램의 이해와 활용 v1.1R 프로그램의 이해와 활용 v1.1
R 프로그램의 이해와 활용 v1.1
 
Logstash, ElasticSearch, Kibana
Logstash, ElasticSearch, KibanaLogstash, ElasticSearch, Kibana
Logstash, ElasticSearch, Kibana
 
[1A5]효율적인안드로이드앱개발
[1A5]효율적인안드로이드앱개발[1A5]효율적인안드로이드앱개발
[1A5]효율적인안드로이드앱개발
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8
 
배워봅시다 머신러닝 with TensorFlow
배워봅시다 머신러닝 with TensorFlow배워봅시다 머신러닝 with TensorFlow
배워봅시다 머신러닝 with TensorFlow
 
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
 
StarUML NS Guide - Design
StarUML NS Guide - DesignStarUML NS Guide - Design
StarUML NS Guide - Design
 
집단지성 프로그래밍 03-군집발견-03
집단지성 프로그래밍 03-군집발견-03집단지성 프로그래밍 03-군집발견-03
집단지성 프로그래밍 03-군집발견-03
 
Python machine learning Ch.4
Python machine learning Ch.4Python machine learning Ch.4
Python machine learning Ch.4
 
Software Development Process - Korean
Software Development Process - KoreanSoftware Development Process - Korean
Software Development Process - Korean
 
Scala for play
Scala for playScala for play
Scala for play
 
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613
 
Django를 Django답게, Django로 뉴스 사이트 만들기
Django를 Django답게, Django로 뉴스 사이트 만들기Django를 Django답게, Django로 뉴스 사이트 만들기
Django를 Django답게, Django로 뉴스 사이트 만들기
 
KCSE 2015 Tutorial 빅데이터 분석 기술의 소프트웨어 공학 분야 활용 (...
KCSE 2015 Tutorial 빅데이터 분석 기술의  소프트웨어 공학 분야 활용 (...KCSE 2015 Tutorial 빅데이터 분석 기술의  소프트웨어 공학 분야 활용 (...
KCSE 2015 Tutorial 빅데이터 분석 기술의 소프트웨어 공학 분야 활용 (...
 
2017 AWS DB Day | 개발자가 알아야 할 Amazon DynamoDB 활용법
2017 AWS DB Day | 개발자가 알아야 할 Amazon DynamoDB 활용법 2017 AWS DB Day | 개발자가 알아야 할 Amazon DynamoDB 활용법
2017 AWS DB Day | 개발자가 알아야 할 Amazon DynamoDB 활용법
 
강의자료4
강의자료4강의자료4
강의자료4
 
Python 활용: 이미지 처리와 데이터 분석
Python 활용: 이미지 처리와 데이터 분석Python 활용: 이미지 처리와 데이터 분석
Python 활용: 이미지 처리와 데이터 분석
 
Ots2014 arcus-collection-open source
Ots2014 arcus-collection-open sourceOts2014 arcus-collection-open source
Ots2014 arcus-collection-open source
 

Serverless content recommendation

  • 2. Kurt Lee Technical Leader, Vingle Inc iOS / Frontend / Backend kurt@vingle.net https://github.com/breath103
  • 3. 목표: 
 “사용자의 반응에 기반하여,
 새로운 컨텐츠 추천”
  • 4. 1. Item-Item Collaborative Filtering 2. Serverless Data Pipeline for CF
  • 6.
  • 7. A가 B를 샀다 B를 사면 C도 산다 A는 C를 살 것이다.
  • 8. A. User-Item Approach B. Item-Item Approach SageMaker / Tensorflow 등으로 가능 S3 + Athena 등으로 가능
  • 9. A. User-Item Approach Assume)
 Rating(U, I) = UserFeatures[U] * ItemFeatures[I]
  • 10. SageMaker Factorization Machine
 (https://docs.aws.amazon.com/sagemaker/latest/dg/fact-machines.html) Spark ML
 (EMR) Collborative Filtering
 (https://spark.apache.org/docs/latest/ml-collaborative-filtering.html)
  • 11. A. User-Item Approach 1) it requires training 2) it requires massive data to store
 User * Features + Item * Features 3) it gets really expensive when it get’s big
 O(user * item)
  • 13. User의 ItemA에 대한 예상 점수 = AVG(User가 이미 평가한 ItemB의 점수 * ItemB와 ItemA의 유사도 점수) User의 ItemA에 대한 예상 점수 ( “Like” 만 있을때 ) = AVG(User가 좋아한 ItemB와 ItemA의 유사도 점수) 내가 A, B를 Like했고, S(A, C) = 0.5, S(B, C) = 0.8 이면,
 나의 C에 대한 예상 점수 = (0.5 + 0.8) / 2 = 0.65
  • 14. 장점 1)User-Item Rating, Item-Item Similarity 두개만 관리하면되서, 사이즈가 훨씬 작음.
 (특히, Item 갯수가 User 갯수에 비해 작을땐)
 2)자연스럽게 Item-Item Similarity를 알게 되기 때문에, 
 "요 Item의 Related Items..." 를 일석이조
  • 15. 주어진 아이템 A, B의 “유사성”은 
 어떻게 점수화?
  • 17. 다양한 변형 (Tanimoto, Sigmoid, …) 이 있지만, 
 공통적인 가장 중요한 특성은,
  • 18. A = A를 좋아한 사람 숫자 B = B를 좋아한 사람 숫자 A ⋂ B = A와 B를 모두 좋아한 사람 숫자 ex)
  • 19. 참고: 여러가지 Jaccard Similarity Function을 비교해 봤는데, 
 Sigmoid Jaccard가 가장 퍼포먼스 좋았습니다. http://www.semantic-web-journal.net/system/files/swj1740.pdf
  • 22. 데이터 수집이 잘 되어있다는 가정하에… 1) Item-Item Jaccard Score를 Athena에서 계산해서, 
 Aurora로 "LOAD FROM"
 2) User-Item을 Athena에서 정리하여, 
 Aurora로 "LOAD FROM"
 3) Lambda에서, UserId로 두 table을 조회하여 계산
  • 23. 빠르게 접근 가능해야 하는 데이터 1) Interest - Interest 연관도
 Array<{ A, B, Score (0~1) }> 2) “내가” 최근에 좋아한 Interest 목록
 Array<{ user, interest }>
  • 24. Interest-Interest score A = A를 방문한 사람 B = B를 방문한 사람 A ⋂ B = A와 B를 모두 방문한 사람
  • 25. Interest-Interest score WITH interest_reads AS ( SELECT user_id, content_id as interest FROM user_actions WHERE (year || month || day) > date_format(CURRENT_TIMESTAMP - interval '30' DAY, '%Y%m%d') GROUP BY 1, 2 ), ab_inner_reads_count AS ( SELECT a.interest AS a, b.interest AS b, count(1) AS count FROM interest_reads a JOIN interest_reads b ON a.user_id = b.user_id AND a.interest < b.interest GROUP BY 1, 2 ), reads_count AS ( SELECT interest, count(1) AS count FROM interest_reads GROUP BY 1 ), similarity AS ( SELECT innerCnt.a AS a, innerCnt.b AS b, (innerCnt.count / (aCount.count + bCount.count - innerCnt.count)) AS score FROM ab_inner_reads_count AS innerCnt JOIN reads_count AS aCount ON aCount.interest = innerCnt.a JOIN reads_count AS bCount ON bCount.interest = innerCnt.b ) SELECT * FROM similarity [user_id, interest] [A, count] [A, B, count]
 To avoid [B, A, count], a < b [A, B, count] JOIN [A, count] JOIN [B, count] [A, B, score]
  • 26. Record가 너무 많음.
 Item이 n개일때, n*n 개... 30000 => 900,000,000
  • 27. S3에는 문제 없지만, 
 Aurora에 넣으면 너무 비쌈
  • 28. [A, B, 0.5] [A, C, 0.3] [A, D, 0.2] [A, "(B, 0.5), (C, 0.3), (D, 0.2)"] ARRAY_AGG!
  • 29. (year || month || day) > date_format(CURRENT_TIMESTAMP - interval '30' DAY, '%Y%m%d') GROUP BY 1, 2 ), ab_inner_reads_count AS ( SELECT a.interest AS a, b.interest AS b, count(1) AS count FROM interest_reads a JOIN interest_reads b ON a.user_id = b.user_id AND a.interest < b.interest GROUP BY 1, 2 ), reads_count AS ( SELECT interest, count(1) AS count FROM interest_reads GROUP BY 1 ), similarity AS ( SELECT innerCnt.a AS a, innerCnt.b AS b, (innerCnt.count / (aCount.count + bCount.count - innerCnt.count)) AS score FROM ab_inner_reads_count AS innerCnt JOIN reads_count AS aCount ON aCount.interest = innerCnt.a JOIN reads_count AS bCount ON bCount.interest = innerCnt.b ) SELECT a, 
 json_format( CAST( array_agg( ROW(b, score) ) AS JSON ) ) as cards FROM similarity GROUP BY 1 [A, "[[B, 0.1], [C, 0.2]....]"]
 [B, "[[C, 0.1], [D, 0.2]....]"]
  • 30. LOAD DATA FROM S3 's3://vingle-redshift/athena_output.csv' REPLACE INTO TABLE interest_similarity CHARACTER SET 'utf8mb4' FIELDS TERMINATED BY ',' ENCLOSED BY '"' IGNORE 1 ROWS (@interest, @others) SET interest = @interest, others = @others, created_at = CURRENT_TIMESTAMP; CREATE TABLE `interest_similarity` ( `interest` VARCHAR(50) NOT NULL, `others` text COLLATE utf8mb4_bin NOT NULL, `created_at` datetime NOT NULL, PRIMARY KEY (`interest`) ) Aurora로 Load!
  • 32. User-Recently-Visited-Interest WITH interest_reads AS ( SELECT session_data.user_id, data.content.id as interest FROM track_tickets.user_content_action WHERE (year || month || day) > date_format(CURRENT_TIMESTAMP - interval '30' DAY, '%Y%m%d') GROUP BY 1, 2 ) SELECT user_id, json_format(CAST(array_agg(ROW(interest)) AS JSON)) as interests FROM interest_reads GROUP BY 1 [user_id, "[['A'], ['B'], ....]"]
  • 33. LOAD DATA FROM S3 's3://vingle-redshift/athena_output.csv' REPLACE INTO TABLE user_interest CHARACTER SET 'utf8mb4' FIELDS TERMINATED BY ',' ENCLOSED BY '"' IGNORE 1 ROWS (@user_id, @others) SET user_id = @user_id, others = @others, created_at = CURRENT_TIMESTAMP; CREATE TABLE `user_interest` ( `user_id` INT NOT NULL, `others` text COLLATE utf8mb4_bin NOT NULL, `created_at` datetime NOT NULL, PRIMARY KEY (`user_id`) ) Aurora로 Load!
  • 35. async function recommendedInterests(userId: number) { const visitedInterests = JSON.parse( (await UserVisitedInterests.find(userId)).others ) as Array<string>; // [interest, "[[A, score], [B, score]]"]... const related = await InterestInterestSimilarity.findAll({ interest: visitedInterests }); return _.chain(visitedInterests) .flatMap((base) => { const similarItems = related.find(i => i.interest === base); // How much user likes interest. 1 for every interests now return ( JSON.parse(similarItems.others) as Array<[string, number]> ).map(item => { return { interest: item[0], score: item[1] * (1.0) /** base.score */, }; }); }) .groupBy(i => i.interest) .mapValues(items => _.chain(items).map(i => i.score).sum().value() / items.length ) .sortBy(i => - i.score) .value(); }
  • 37. S3 + Athena + Aurora 조합 무거운 쿼리는 Athena로, 빠른 Access가 필요한 결과물은Aurora로 데이터 수집은 Firehose + S3로 + 진리의 JSON Athena도 API로, Cron Cloudwatch Cron => Lambda => Athena => Aurora
  • 38. QnA