Elastic Stack 과 Apache mahout 을 이용한 추천 데이터 생성을 다뤄 볼까 합니다.
기본적으로는 Elastic Stack 만 가지고도 cohort 분석을 통해 추천 데이터 마트 구성이 가능 한데요.
추천 데이터에 대한 품질을 좀 더 좋게 하기 위해 Apache mahout 을 활용해 보도록 하겠습니다.
여기서 다루는 내용은 누구나 쉽게 접근 할 수 있도록 Hello World! 수준만 기술 합니다.
[Elastic Stack]
https://www.elastic.co/products
[Apache mahout]
https://mahout.apache.org/
위 두 솔루션은 모두 오픈소스 이며 예제 코드가 해당 소스에 잘 만들어져 있어 누구나 쉽게 활용이 가능합니다.
Step 1)
Elasticsearch + Logstash + Kibana 를 이용해 로그를 수집하고 추천 할 raw data 를 생성 합니다.
User item click log -> Logstash collect -> Elasticsearch store -> Kibana visualize -> CSV download
여기서 수집한 데이터 중 추출 데이터는 user id + item id + click count 입니다.
아래는 Kibana QueryDSL 예제 입니다.
{
"size": 0,
"query": {
"filtered": {
"query": {
"query_string": {
"query": "cp:CLK AND id:[0 TO *]",
"analyze_wildcard": true
}
},
"filter": {
"bool": {
"must": [
{
"range": {
"time": {
"gte": 1485010800000,
"lte": 1485097199999,
"format": "epoch_millis"
}
}
}
],
"must_not": []
}
}
}
},
"aggs": {
"2": {
"terms": {
"field": "user_id",
"size": 30000,
"order": {
"_count": "desc"
}
},
"aggs": {
"3": {
"terms": {
"field": "item_id",
"size": 10,
"order": {
"_count": "desc"
}
}
}
}
}
}
}
Step 2)
Apache mahout 에서 사용할 recommender 는 UserBasedRecommender 입니다.
샘플 코드에도 나와 있지만 dataset.csv 파일은 아래와 같은 형식 입니다.
- Creating a User-Based Recommender in 5 minutes
1,10,1.0
1,11,2.0
1,12,5.0
1,13,5.0
형식) userId,itemId,ratingValue
Step1 에서 위와 같은 형식을 맞추기 위해 user_id, item_id, click_count 를 생성 하였습니다.
이 데이터를 기반으로 UserBasedRecommender 를 돌려 보도록 하겠습니다.
Step 3)
아래 보시면 샘플 코드가 잘 나와 있습니다.
https://github.com/apache/mahout/tree/master/examples/src/main/java/org/apache/mahout
Main class 하나 만드셔서 Step2 에 나와 있는 코드로 돌려 보시면 됩니다.
저는 UserBasedRecommender 를 implements 해서 별도로 구현했습니다.
이건 누구나 쉽게 하실 수 있는 부분이기 때문에 examples 에 나와 있는 BookCrossingRecommender 클래스등을 참고 하시면 됩니다.
UserBasedRecommenderRunner runner = new UserBasedRecommenderRunner();
Recommender recommender = runner.buildRecommender();
// 710039번 유저에 대한 추천 아이템 3개
List<RecommendedItem> recommendations = recommender.recommend(710039, 3);
for (RecommendedItem recommendation : recommendations) {
LOG.debug("추천 아이템 : {}", recommendation);
}
[실행 로그]
11:39:31.527 [main] INFO o.a.m.c.t.i.model.file.FileDataModel - Creating FileDataModel for file /git/prototype/data/user-to-item.csv
11:39:31.626 [main] INFO o.a.m.c.t.i.model.file.FileDataModel - Reading file info...
11:39:31.765 [main] INFO o.a.m.c.t.i.model.file.FileDataModel - Read lines: 63675
11:39:31.896 [main] INFO o.a.m.c.t.i.model.GenericDataModel - Processed 10000 users
11:39:31.911 [main] INFO o.a.m.c.t.i.model.GenericDataModel - Processed 19124 users
11:39:31.949 [main] DEBUG o.a.m.c.t.i.r.GenericUserBasedRecommender - Recommending items for user ID '710039'
11:39:31.965 [main] DEBUG o.a.m.c.t.i.r.GenericUserBasedRecommender - Recommendations are: [RecommendedItem[item:35222, value:4.0], RecommendedItem[item:12260, value:4.0], RecommendedItem[item:12223, value:1.5]]
11:39:31.966 [main] DEBUG o.h.p.mahout.meme.MemeProductRunner - 추천 아이템 : RecommendedItem[item:35222, value:4.0]
11:39:31.966 [main] DEBUG o.h.p.mahout.meme.MemeProductRunner - 추천 아이템 : RecommendedItem[item:12260, value:4.0]
11:39:31.967 [main] DEBUG o.h.p.mahout.meme.MemeProductRunner - 추천 아이템 : RecommendedItem[item:12223, value:1.5]
[Recommender]
similarity = new PearsonCorrelationSimilarity(dataModel);
// 이웃한 N명의 사용자 데이터로 추천 데이터 생성
// UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, dataModel, 0.2);
// 특정 값이나 임계치를 넘는 모든 사용자의 데이터로 추천 데이터 생성, samplingrate : user sampling rate 10%
// UserNeighborhood neighborhood = new ThresholdUserNeighborhood(0.1, similarity, dataModel, 0.1);
UserNeighborhood neighborhood = new ThresholdUserNeighborhood(0.2, similarity, dataModel, 1.0);
recommender = new GenericUserBasedRecommender(dataModel, neighborhood, similarity);
- 데이터 크기가 너무 작아 ThresholdUserNeighborhood 를 이용하였습니다.
이와 같이 검색 클릭 로그를 기반으로 CF를 돌려 추천 데이터를 만드는 아주 간단한 방법을 알아봤습니다.
만든 추천 데이터에 대한 평가도 가능 합니다.
역시 examples 에 xxxxxxEvaluator 클래스들을 참고하셔서 구현해 보시면 됩니다.