본문 바로가기
IT 실무

주간, 월간, 실시간 랭킹 구현하기

by 지식id 2015. 7. 19.
반응형

쉽게 생각하면 랭킹 구현은 어렵지 않다. 그냥 ORDER BY로 줄을 세워주면 그게 랭킹이다. 순위의 기준이 되는 값은 계속 쌓이고 그에 따라 랭킹을 출력해 주는 이런 랭킹을 '누적랭킹' 이라고 할수 있다. 하지만 이런 누적랭킹은 많이 사용되지 않는다. 많이 사용되는 랭킹은 기간별 랭킹과 실시간 랭킹이다.


1. 기간별 랭킹

기간별 랭킹은 월간, 주간과 같이 특정 기간동안의 랭킹을 구현하는 것이다. 이 또한 쉽게 생각하자면 아주 쉽다.


int key 

date ref_month

int score


위와 같은 구조의 테이블만 있으면 된다. 예를 들어 어떤 음악이 재생되고 다운받아 지는 횟수에 따라 월간 랭킹을 구현하고 싶다고 가정해 보자. 


key는 해당 곡의 key값이 된다. foreign key가 될 것이다. 

*이 테이블의 PM으로 사용될 순 없다. 이 테이블의 PM은 key + date가 되거나 별도의 PM용 필드가 있어야 한다.

date에는 2015-07-01과 같은 날짜가 들어가는데 날짜는 무의미하다. 2015-07까지만 사용될 것이다.

score에는 음악이 재생되고 다운받아 질때마다 점수는 1점, 2점씩 쌓아준다.


어떤 곡을 재생 했는데 key가 현재 곡의 key이고 date의 년월 값이 현재 년월값과 일치하는 row가 없을 경우, 즉 

WHERE key = '$song_id' AND ref_month LIKE '2015-07%' 인 row가 없다면 

(key, ref_month, score) VALUES ('$song_id', '2015-07-01', 1) 인 row를 하나 만들어 준다.

만약 있다면 score의 값만 누적해서 쌓아주면 된다.


이렇게 되면 2015-08-01이후부터는 기존 row에 점수 누적이 중단되고 ref_month가 2015-08-01인 새로운 row가 생겨날 것이다.

이렇게 까지만 구현 해 놓으면 우리는 이 태이블에서 순위를 출력하고 싶은 달만 선택해서 score 순으로 출력 해 주면 된다.


SELECT key FROM rank WHERE ref_month LIKE '2015-07%' ORDER BY 'score' DESC


하지만 문제가 있다! 이렇게 할 경우 달이 바뀌는 그 시점에는 점수가 모두 0이기 때문에 2015-08-01에는 출력을 할 기준이 없어지게 된다. 위에서 구현한대로 그대로 출력만 해 주게 되면 8월 1일의 랭킹은 거의 무작위로 출력될 것이고, 현재 보여지는 랭킹이 순위 형성에 영향을 끼치게 된다면 신뢰성 있는 랭킹에 좋지 않은 영향을 끼치게 될 수 밖에 없다.


이 문제를 해결하기 위해 아래와 같은 여러 방법을 사용할 수 있다.


(1) 이번달 랭킹은 없다. 월간 랭킹은 지나간 과거 월의 랭킹만 보여준다. 

 - 2015-08-01이 되어서야 2015-07월의 랭킹을 보여주고 이때부터 8월달 랭킹을 위한 점수를 쌓았다가 또 9월이 되어서야 8월 랭킹을 보여준다. 정보의 실시간성이 요구되지 않는 경우엔 이렇게 구현해도 문제가 없다. 하지만 많은 경우에서 사용자들은 이런식의 랭킹을 원하지 않을 가능성이 높다. 최신 인기곡을 듣고 싶은 사람들이 항상 전 달의 인기곡만 볼 수 있다면 문제가 될것이다.


(2) 이번달의 일정 기간이 지나고 부터 이번달 랭킹을 보여준다.

 - 1번의 방법을 조금 보완한 방식이다. 2015-08-01이 되어도 2015-07월의 랭킹을 그대로 보여준다. 그리고 8월달의 점수를 쌓다가 점수가 어느정도 쌓인 2015-08-07이 되면 그때부터 8월달의 랭킹을 보여준다. 이렇게 되면 일주일씩 느리긴 하지만 그래도 한달 중 3주 이상은 현재월의 랭킹을 정확히 확인 할 수 있다. 단점이라면 8월 첫째주까지는 변동이 별로 없다가 8월 7일에 갑자기 큰 변화가 생기며 그 시기부터 변동도 빨라진다는 것이다. (쌓인데이터가 많지 않기 때문에 순위가 뒤바뀔 가능성이 크다.)


(3) 일별(또는 주별로)로 점수를 쌓고 최근 한달간의 랭킹을 보여준다.

 - 테이블에 저장되는 값은 일자별로 매일 생겨난다. 그리고 지금 날짜로 부터 과거 한달간의 데이터를 모두 가져와 합산한 점수를 토대로 랭킹을 줄력한다. 가장 정확한 방법이지만 테이블의 row가 30배로 늘어나고 연산또한 무거워 진다는 단점이 있다. 이를 보완하기 위해서 일자별 까지는 아니고 주별로 데이터를 저장해서 같은 방식으로 구현할 수 있다. 또는 최대 과거 몇달까지의 데이터만 저장하고 배치작업을 통해 데이터를 주기적으로 지워서 테이블을 가볍게 해 주는 방법도 있다. 


만약 현재 날짜인 2015년 7월 19일의 7월달 랭킹을 보여 주려면

SELECT key FROM rank WHERE ref_date > '2015-06-19' ORDER BY 'score' DESC


과거인 5월달의 랭킹을 보여 주려면

SELECT key FROM rank WHERE ref_date >= '2015-05-01' AND ref_date <= '2015-05-31' ORDER BY 'score' DESC


와 같이 구현하면 될 것이다.


이와 같은 방법들을 사용하면 주간 랭킹, 일간 랭킹또한 구현하는데 문제가 없을 것이다.


2. 실시간 랭킹

반응형

댓글