[Spring Boot] 뉴스피드 프로젝트에 유저의 팔로잉을 고려한 피드 추천 기능 구현하기
팔로잉, 좋아요, 작성일자에 따라 가중치를 계산하여 유저에게 각기 다른 정렬로 피드를 추천하여 보여주는 기능을 구현해보았다.
- 가중치는 로그인 유저(팔로잉 가능)와 게스트 유저(팔로잉 불가)의 role에 따라 다르게 계산하여 보여준다.
- 로그인 유저 가중치 : 팔로잉 여부(0.5) + 좋아요 수(0.4) + 작성일자(0.1)
- 게스트 유저 가중치 : 좋아요 수(0.8) + 작성일자(0.2)
이 기능을 구현하기 위해 생각한 방법은 유저가 뉴스 피드 페이지를 조회하면 모든 피드들의 가중치를 계산하고 저장한 뒤 내림차순 정렬한 결과를 보여주는 것이다.
@Transactional
public void calculateWeightForUser(User user){
// 로그인 유저 피드 정렬 기준 가중치 = 팔로우(0.5) + 좋아요(0.4) + 작성일(0.1)
double maxLikes = postRepository.findTopByOrderByLikesCountDesc().getLikesCount();
for(Post post : postRepository.findAll()) {
double followScore = 0;
if(followRepository.findByUserIdAndFollowUserId(user.getId(), post.getUser().getId()).isPresent()) {
followScore = FOLLOW;
}
double likeScore = post.getLikesCount() / maxLikes * LIKE;
LocalDateTime now = LocalDateTime.now();
long daysBetween = ChronoUnit.DAYS.between(post.getCreatedAt(), now);
double dateScore = DATE * Math.exp(-daysBetween);
post.setWeight(followScore + likeScore + dateScore);
}
}
우선 FOLLOW, LIKE, DATE의 가중치 비율을 상수로 저장해두고 모든 포스트를 순회하며 각각을 조회하여 업데이트 한 뒤 계산하여 저장하는 메서드를 생성하였다.
1. followRepository를 조회하여 해당 유저가 포스트를 작성한 유저를 팔로우 하는 경우, 0.5의 가중치를 더한다.
2. 좋아요의 최대값을 미리 저장해둔 뒤, 포스트의 좋아요수 / 최대 좋아요 수 * 0.4를 하여 가중치를 더한다.
3. 현재 날짜와 포스트 작성 날짜의 일수 차이를 계산한 뒤 0.1을 곱해 가중치를 더한다.
게스트 로그인일 경우 위의 가중치 설계에 따라 다르게 계산한다.
@Transactional
public Page<PostResponseDto> getAllPosts(... UserDetailsImpl userDetails) {
if(userDetails == null) {
calculateWeightForGuests();
} else{
calculateWeightForUser(userDetails.getUser());
}
Sort sort = Sort.by(Sort.Direction.DESC, "weight");
Pageable pageable = PageRequest.of(page, size, sort);
이후 getAllPosts 메서드에서 유저의 권한에 따라 계산을 해주고 sort 기준을 가중치 내림차순으로 지정한 뒤, page를 조회한다.
우선 이렇게 구현을 하였지만 유저가 조회할 때마다 모든 포스트의 가중치를 계산하는 것은 비효율적이지 않을까? 라는 생각이 들었다. 조언을 구하였더니 해당 가중치를 구하는 계산 과정을 포스트에 저장하지 않고 sql에서 처리하여 정렬할 수 있으며 이 방법이 가장 효율적이라고 알려주셨다. 다만 현재는 spring boot로만 구현을 하고 있고 DB와 관련된 부분은 추후에 회사에 가서 생각해도 괜찮으니 당장은 백엔드에서 로직을 처리하도록 구현해도 무방하다고도 하셨다.
코드가 잘 실행되다가 어떤 환경에서 weight에 NAN 값이 들어갔다며 코드가 제대로 실행되지 않는 오류가 발생했다. 이것은 값을 0으로 나누어 발생한 오류이며 maxLikes가 0일 경우를 고려하지 않아서 좋아요가 한 개도 없을 때 해당 오류가 발생하였다. maxLikes가 0일 경우 1로 바꿔줌으로써 문제를 해결하였다.
기준에 따라 가중치를 구하여 잘 출력된다!