diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt index d696918f..656ed0a2 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt @@ -686,17 +686,10 @@ class DefaultHomeRecommendationQueryRepository( and ccc.created_at >= :windowStart and ccc.created_at < :windowEndExclusive group by ccc.creator_community_id - ), - follower_stats as ( - select cf.creator_id as creator_id, count(distinct cf.id) as follower_count - from creator_following cf - where cf.is_active = true - group by cf.creator_id ) select cc.id as target_id, ((coalesce(ls.like_count, 0) * ${RecommendationScoreSpec.COMMUNITY_LIKE_WEIGHT} + - (case when cc.is_comment_available = true then coalesce(cs.comment_count, 0) else 0 end) * ${RecommendationScoreSpec.COMMUNITY_COMMENT_WEIGHT} + - coalesce(fs.follower_count, 0) * ${RecommendationScoreSpec.COMMUNITY_FOLLOWER_WEIGHT}) * + (case when cc.is_comment_available = true then coalesce(cs.comment_count, 0) else 0 end) * ${RecommendationScoreSpec.COMMUNITY_COMMENT_WEIGHT}) * case when cd.debut_at >= :boost10Start then ${RecommendationScoreSpec.COMMUNITY_NEW_BOOST_10_DAYS} when cd.debut_at >= :boost20Start then ${RecommendationScoreSpec.COMMUNITY_NEW_BOOST_20_DAYS} @@ -709,7 +702,6 @@ class DefaultHomeRecommendationQueryRepository( join creator_debut cd on cd.creator_id = cc.member_id left join like_stats ls on ls.community_id = cc.id left join comment_stats cs on cs.community_id = cc.id - left join follower_stats fs on fs.creator_id = cc.member_id where cc.is_active = true and m.is_active = true and cc.price <= 0 @@ -719,7 +711,6 @@ class DefaultHomeRecommendationQueryRepository( and ( coalesce(ls.like_count, 0) > 0 or (cc.is_comment_available = true and coalesce(cs.comment_count, 0) > 0) - or coalesce(fs.follower_count, 0) > 0 ) order by score desc, random_tie_breaker asc limit :limit diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt index f44ea336..fcac5d89 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt @@ -936,7 +936,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( } @Test - @DisplayName("인기 커뮤니티 스냅샷은 좋아요 댓글 팔로워 수를 distinct로 집계하고 댓글 불가 게시글은 댓글 수 0으로 계산한다") + @DisplayName("인기 커뮤니티 스냅샷은 좋아요와 댓글 수를 distinct로 집계하고 follower-only 게시글은 제외한다") fun shouldFindPopularCommunitySnapshotsWithDistinctCounts() { val windowStart = LocalDateTime.of(2026, 5, 23, 0, 0) val snapshotAt = LocalDateTime.of(2026, 5, 29, 23, 59, 59) @@ -977,17 +977,10 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( val expectedPostScore = scorePolicy.calculateCommunityScore( likeCount = 2, commentCount = 2, - followerCount = 2, - newBoost = scorePolicy.calculateCommunityCreatorNewBoost(LocalDateTime.of(2026, 4, 1, 12, 0), snapshotAt) - ) - val expectedCommentDisabledScore = scorePolicy.calculateCommunityScore( - likeCount = 0, - commentCount = 0, - followerCount = 2, newBoost = scorePolicy.calculateCommunityCreatorNewBoost(LocalDateTime.of(2026, 4, 1, 12, 0), snapshotAt) ) assertEquals(expectedPostScore, snapshots[post.id]!!.score, 0.0001) - assertEquals(expectedCommentDisabledScore, snapshots[commentDisabledPost.id]!!.score, 0.0001) + assertEquals(false, snapshots.containsKey(commentDisabledPost.id)) } @Test @@ -1040,7 +1033,6 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( val expectedScore = scorePolicy.calculateCommunityScore( likeCount = 1, commentCount = 0, - followerCount = 0, newBoost = scorePolicy.calculateCommunityCreatorNewBoost(LocalDateTime.of(2026, 5, 20, 0, 0), snapshotAt) ) assertEquals(1, snapshots.size) @@ -1050,17 +1042,19 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( } @Test - @DisplayName("인기 커뮤니티 스냅샷은 좋아요 댓글 팔로워가 모두 0인 게시글을 제외한다") + @DisplayName("인기 커뮤니티 스냅샷은 좋아요와 댓글이 모두 0인 게시글을 제외한다") fun shouldExcludeZeroMetricPopularCommunitySnapshots() { val windowStart = LocalDateTime.of(2026, 5, 23, 0, 0) val snapshotAt = LocalDateTime.of(2026, 5, 29, 23, 59, 59) val windowEndExclusive = snapshotAt.plusSeconds(1) val creator = saveMember("zero-community-creator", MemberRole.CREATOR) val liker = saveMember("zero-community-liker", MemberRole.USER) + val follower = saveMember("zero-community-follower", MemberRole.USER) saveLiveRoom(creator, LocalDateTime.of(2026, 5, 10, 12, 0), channelName = "zero-community-live") val zeroPost = saveCommunity(creator, isCommentAvailable = true) val scoredPost = saveCommunity(creator, isCommentAvailable = true) val like = saveCommunityLike(liker, scoredPost, isActive = true) + saveFollowing(follower, creator, isActive = true) updateCreatedAt("CreatorCommunity", zeroPost.id!!, windowStart.plusDays(1)) updateCreatedAt("CreatorCommunity", scoredPost.id!!, windowStart.plusDays(1)) updateCreatedAt("CreatorCommunityLike", like.id!!, windowStart.plusDays(1)) @@ -1170,7 +1164,6 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( val expectedCommunityScore = scorePolicy.calculateCommunityScore( likeCount = 1, commentCount = 0, - followerCount = 0, newBoost = scorePolicy.calculateCommunityCreatorNewBoost(firstLiveAt, snapshotAt) ) assertEquals(expectedCheerScore, cheerSnapshot.score, 0.0001) @@ -1217,7 +1210,6 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( val expectedCommunityScore = scorePolicy.calculateCommunityScore( likeCount = 1, commentCount = 0, - followerCount = 0, newBoost = scorePolicy.calculateCommunityCreatorNewBoost(contentDebutAt, snapshotAt) ) assertEquals(expectedCheerScore, cheerSnapshot.score, 0.0001)