Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class FriendRecommender {
private final PlaygroundUserIdsProvider playgroundUserIdsProvider;
private final PlatformService platformService;

private static final int MAX_OVERSAMPLE = 50;

public RecommendedFriendsRequest recommendFriendsByTypeList(List<FriendRecommendType> typeList, int size,
Long userId) {
typeList = this.adjustTypeList(typeList);
Expand All @@ -37,7 +39,7 @@ public RecommendedFriendsRequest recommendFriendsByTypeList(List<FriendRecommend
List<RecommendedFriendsByType> recommendedFriends = new ArrayList<>();
for (FriendRecommendType type : typeList) {
List<UserProfile> recommendableUserProfiles =
this.getRecommendableUserProfiles(type, ownProfile, friendFilter);
this.getRecommendableUserProfiles(type, ownProfile, friendFilter, size);
if (!recommendableUserProfiles.isEmpty()) {
List<UserProfile> pickedUserProfiles = RandomPicker.pickRandom(recommendableUserProfiles, size);
List<SimplePokeProfile> simplePokeProfiles =
Expand Down Expand Up @@ -75,17 +77,37 @@ private List<SimplePokeProfile> makeSimplePokeProfilesForNotFriend(
}

private List<UserProfile> getRecommendableUserProfiles(
FriendRecommendType type, OwnPlaygroundProfile ownProfile, FriendFilter friendFilter) {
FriendRecommendType type, OwnPlaygroundProfile ownProfile, FriendFilter friendFilter, int size) {
// size 가드 : 이상값 들어오면 500 대신 빈 리스트
if (size <= 0) return List.of();

// ALL_USER 아닐 경우 playground에서 후보 id 수집
Set<Long> userIds;
if (type == FriendRecommendType.ALL_USER) {
userIds = Set.copyOf(userService.getAllUserIds());
} else {
userIds = playgroundUserIdsProvider.findPlaygroundIdsByType(ownProfile, type);
}
if (userIds.isEmpty()) return List.of();

List<Long> candidates = new ArrayList<>(userIds);

// oversample: size*5 (최대 50). 플랫폼 요청 URI 길이 보호(414 방지), friendFilter 탈락 대비 여유 확보 목적.
int oversampleCount = Math.min(MAX_OVERSAMPLE, size *5);
oversampleCount = Math.min(oversampleCount, candidates.size());

// 플랫폼 조회 전 ID를 oversampleCount 만큼만 추출 (URI 길이 보호, 414 방지)
List<Long> toLookup = (candidates.size() <= oversampleCount)
? candidates
: RandomPicker.pickRandom(candidates, oversampleCount);

// 플랫폼에서 유저 정보 조회
List <UserProfile> unFilteredUserProfiles = platformService.getPlatformUserInfosResponse(List.copyOf(toLookup))
.stream()
.map(user -> UserProfile.of((long)user.userId(), user.name()))
.toList();

List <UserProfile> unFilteredUserProfiles = platformService.getPlatformUserInfosResponse(List.copyOf(userIds))
.stream()
.map(user -> UserProfile.of((long)user.userId(), user.name())).toList();
// 이미 친구인 유저 제외(앱 내 filter)
return friendFilter.excludeAlreadyFriendUserIds(unFilteredUserProfiles);
}

Expand Down
18 changes: 8 additions & 10 deletions src/main/java/org/sopt/app/common/utils/RandomPicker.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,19 @@
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
public class RandomPicker {

private static final Random random = new Random();

public static <T> List<T> pickRandom(List<T> data, int pickLimit) {
if (data.size() <= pickLimit) {
return new ArrayList<>(data);
}
int n = data.size();
if (pickLimit <= 0 || n == 0) return List.of(); // 가드
if (pickLimit >= n) return new ArrayList<>(data); // 전부 반환

int[] indices = IntStream.range(0, data.size()).toArray();
List<T> randomList = new ArrayList<>();
int[] indices = IntStream.range(0, n).toArray();
List<T> randomList = new ArrayList<>(pickLimit);
for (int i = 0; i < pickLimit; ++i) {
int randomIndex = random.nextInt(data.size() - i);
int randomIndex = java.util.concurrent.ThreadLocalRandom.current().nextInt(n - i);
randomList.add(data.get(indices[randomIndex]));
indices[randomIndex] = indices[data.size() - 1 - i];
// Fisher–Yates 선택: 사용한 슬롯을 뒤쪽 미사용 구간의 마지막으로 대체
indices[randomIndex] = indices[n - 1 - i];
}
return randomList;
}

}