시험 끝났는데 오히려 더 바쁜 일정이 시작된 요즘..!
뭔가 빈둥거리면 안 되는데 그러고 있어서 살짝 위기감을 느끼는 중입니다.
오늘 작성할 글은 프로젝트를 개발하던 중에,
User들 간에 친구 추천을 할 때 어떤 알고리즘을 사용해서 하면 좋을지 고민하고 구현한 내용입니다.
그렇게 어려운 알고리즘은 아니지만! 좋게 봐주시면 감사하겠습니다. 그리고 피드백은 항상 환영입니다 😎
FOF 알고리즘이란?
fof 알고리즘이란, 말 그대로 Friends Of Friends 알고리즘으로 친구의 친구를 추천해 주는 알고리즘입니다.
사람들이 가장 많이 사용하는 SNS인 인스타그램이나 페이스북, 틱톡 등 다양한 SNS에서 사용하는 알고리즘으로 알고 있는데요!
이를 직접 구현하기 위해서 고민한 내용을 담았습니다.
구현 내용
단순히 친구의 친구를 불러오는 것도 좋은 방법이겠습니다만..!
저는 그렇게 하지는 않고, 공통의 친구(겹치는 친구)가 많을수록 우선순위를 두어서 추천해 주는 알고리즘으로 작성했습니다.
좀 더 자세히 설명을 드리자면,
해시맵 형태로 fof(친구의 친구)를 key로 저장하고, 겹치는 친구가 있을 때마다 value 값을 1씩 증가시킵니다.
그럼 제 fof 중에서 겹지인이 많아질수록 value가 많아지겠죠!
그럼 제가 아는 사람일 확률이 높다고 가정하고, 가장 우선적으로 친구를 추천하는 알고리즘입니다.
아래 코드는 다른 부분을 제외하고 fof과 관련 있는 부분만 남겨놓은 코드입니다.
public List<FriendListResponse> recommendFriends() {
List<FriendListResponse> response = new ArrayList<>();
try {
...
}
Set<User> friends = new HashSet<>(friendList); // 현재 사용자의 친구 목록
Map<User, Integer> recommendationMap = new HashMap<>();
// 친구의 친구들을 찾아서 추천 맵에 추가
for (User friend : friends) {
List<User> fofList = getFriendList(friend);
if (fofList != null) {
for (User fof : fofList) {
if (!friends.contains(fof) && !fof.equals(loginUser)) {
recommendationMap.put(fof, recommendationMap.getOrDefault(fof, 0) + 1);
}
}
}
}
int size = 4;
response = recommendationMap.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.map(Map.Entry::getKey)
.limit(size)
.map(user -> FriendListResponse.builder()
.userId(user.getId())
.nickname(user.getNickname())
.userProfileUrl(user.getProfileURL())
.build())
.collect(Collectors.toList());
} catch (Exception e) {
...
}
return response;
}
예시
예시를 들어서 설명을 하자면,
현재 User가 저와 2번, 3번, 4번, 397번, 398번 유저가 있다고 가정합시다.
그리고 각각의 친구 관계는 위의 표와 같은 상황입니다.
그럼 저와 3번 유저는 친구가 2명 겹치고, 397번 유저와 398번 유저는 1명씩 겹치는 상황입니다.
그렇다면 알고리즘에 의해서 어떻게 우선순위를 두어서 친구를 추천해야 할까요!?
바로....
3, 397, 398 순서로 추천을 해주어야 합니다.
그래서 아래 사진에서 보다시피 POSTMAN을 통해서 API를 호출하면 올바르게 목록이 출력되는 것을 알 수 있습니다.
ETC
이외에도 USER를 추천하는 알고리즘에는 네트워크를 분석해서 추천하는 PageRank 알고리즘도 있다고 하는데요!
현재 MVP를 우선적으로 구현중이라 추후에 리팩토링 할 때 시간이 있다면 PageRank 식으로도 구현을 해보고 싶습니다.
만약 구현하게 된다면 또 글로 설명을 드려볼게요 ㅎㅎ
다음 글을 azure 클라우드 서버 이용 관련 글일 것 같습니다!
긴 글 읽어주셔서 감사하고, 위에서 말한 것처럼 피드백은 언제든 환영입니다.