feat(home): 인기 커뮤니티 점수 정책을 변경한다
This commit is contained in:
@@ -28,6 +28,16 @@ class RecommendationScorePolicy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun calculateCommunityCreatorNewBoost(debutAt: LocalDateTime, now: LocalDateTime): Double {
|
||||||
|
val days = ChronoUnit.DAYS.between(debutAt.toLocalDate(), now.toLocalDate())
|
||||||
|
return when {
|
||||||
|
days <= RecommendationScoreSpec.NEW_BOOST_10_DAY_LIMIT -> RecommendationScoreSpec.COMMUNITY_NEW_BOOST_10_DAYS
|
||||||
|
days <= RecommendationScoreSpec.NEW_BOOST_20_DAY_LIMIT -> RecommendationScoreSpec.COMMUNITY_NEW_BOOST_20_DAYS
|
||||||
|
days <= RecommendationScoreSpec.NEW_BOOST_30_DAY_LIMIT -> RecommendationScoreSpec.COMMUNITY_NEW_BOOST_30_DAYS
|
||||||
|
else -> RecommendationScoreSpec.DEFAULT_NEW_BOOST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun calculateDebutCreatorScore(
|
fun calculateDebutCreatorScore(
|
||||||
followIncrease: Long,
|
followIncrease: Long,
|
||||||
contentActivityScore: Long,
|
contentActivityScore: Long,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ object RecommendationScoreSpec {
|
|||||||
const val CHEER_DONATION_COUNT_WEIGHT = 0.1
|
const val CHEER_DONATION_COUNT_WEIGHT = 0.1
|
||||||
|
|
||||||
const val COMMUNITY_LIKE_WEIGHT = 0.5
|
const val COMMUNITY_LIKE_WEIGHT = 0.5
|
||||||
const val COMMUNITY_COMMENT_WEIGHT = 0.5
|
const val COMMUNITY_COMMENT_WEIGHT = 0.4
|
||||||
const val COMMUNITY_FOLLOWER_WEIGHT = 0.1
|
const val COMMUNITY_FOLLOWER_WEIGHT = 0.1
|
||||||
|
|
||||||
const val NEW_BOOST_10_DAYS = 1.5
|
const val NEW_BOOST_10_DAYS = 1.5
|
||||||
@@ -30,5 +30,8 @@ object RecommendationScoreSpec {
|
|||||||
const val CHEER_NEW_BOOST_10_DAYS = 1.15
|
const val CHEER_NEW_BOOST_10_DAYS = 1.15
|
||||||
const val CHEER_NEW_BOOST_20_DAYS = 1.10
|
const val CHEER_NEW_BOOST_20_DAYS = 1.10
|
||||||
const val CHEER_NEW_BOOST_30_DAYS = 1.05
|
const val CHEER_NEW_BOOST_30_DAYS = 1.05
|
||||||
|
const val COMMUNITY_NEW_BOOST_10_DAYS = 1.15
|
||||||
|
const val COMMUNITY_NEW_BOOST_20_DAYS = 1.10
|
||||||
|
const val COMMUNITY_NEW_BOOST_30_DAYS = 1.05
|
||||||
const val DEFAULT_NEW_BOOST = 1.0
|
const val DEFAULT_NEW_BOOST = 1.0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ class RecommendationSnapshotWindowPolicy {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun previousKstSevenDayUtcWindow(nowUtc: LocalDateTime): RecommendationSnapshotWindow {
|
||||||
|
val dayWindow = previousKstDayUtcWindow(nowUtc)
|
||||||
|
return dayWindow.copy(startUtc = dayWindow.startUtc.minusDays(6))
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val UTC_ZONE: ZoneId = ZoneId.of("UTC")
|
private val UTC_ZONE: ZoneId = ZoneId.of("UTC")
|
||||||
private val KST_ZONE: ZoneId = ZoneId.of("Asia/Seoul")
|
private val KST_ZONE: ZoneId = ZoneId.of("Asia/Seoul")
|
||||||
|
|||||||
@@ -115,17 +115,36 @@ class RecommendationScorePolicyTest {
|
|||||||
@DisplayName("인기 커뮤니티 점수는 좋아요 수, 댓글 수, 팔로우 수에 가중치를 적용한다")
|
@DisplayName("인기 커뮤니티 점수는 좋아요 수, 댓글 수, 팔로우 수에 가중치를 적용한다")
|
||||||
fun shouldCalculateCommunityScore() {
|
fun shouldCalculateCommunityScore() {
|
||||||
assertEquals(0.5, RecommendationScoreSpec.COMMUNITY_LIKE_WEIGHT, 0.0001)
|
assertEquals(0.5, RecommendationScoreSpec.COMMUNITY_LIKE_WEIGHT, 0.0001)
|
||||||
assertEquals(0.5, RecommendationScoreSpec.COMMUNITY_COMMENT_WEIGHT, 0.0001)
|
assertEquals(0.4, RecommendationScoreSpec.COMMUNITY_COMMENT_WEIGHT, 0.0001)
|
||||||
assertEquals(0.1, RecommendationScoreSpec.COMMUNITY_FOLLOWER_WEIGHT, 0.0001)
|
assertEquals(0.1, RecommendationScoreSpec.COMMUNITY_FOLLOWER_WEIGHT, 0.0001)
|
||||||
|
|
||||||
val score = policy.calculateCommunityScore(
|
assertEquals(0.0, policy.calculateCommunityScore(0, 0, 0, 1.0), 0.0001)
|
||||||
likeCount = 40,
|
assertEquals(5.0, policy.calculateCommunityScore(10, 0, 0, 1.0), 0.0001)
|
||||||
commentCount = 20,
|
assertEquals(4.0, policy.calculateCommunityScore(0, 10, 0, 1.0), 0.0001)
|
||||||
followerCount = 100,
|
assertEquals(1.0, policy.calculateCommunityScore(0, 0, 10, 1.0), 0.0001)
|
||||||
newBoost = 1.2
|
assertEquals(38.0, policy.calculateCommunityScore(40, 20, 100, 1.0), 0.0001)
|
||||||
)
|
assertEquals(43.7, policy.calculateCommunityScore(40, 20, 100, 1.15), 0.0001)
|
||||||
|
}
|
||||||
|
|
||||||
assertEquals(48.0, score, 0.0001)
|
@Test
|
||||||
|
@DisplayName("인기 커뮤니티 신규 부스트는 데뷔일 기준 10일/20일/30일 구간을 적용한다")
|
||||||
|
fun shouldApplyCommunityCreatorNewBoostByDebutDays() {
|
||||||
|
val now = LocalDateTime.of(2026, 5, 30, 12, 0)
|
||||||
|
|
||||||
|
assertEquals(1.15, RecommendationScoreSpec.COMMUNITY_NEW_BOOST_10_DAYS, 0.0001)
|
||||||
|
assertEquals(1.10, RecommendationScoreSpec.COMMUNITY_NEW_BOOST_20_DAYS, 0.0001)
|
||||||
|
assertEquals(1.05, RecommendationScoreSpec.COMMUNITY_NEW_BOOST_30_DAYS, 0.0001)
|
||||||
|
assertEquals(1.15, policy.calculateCommunityCreatorNewBoost(now, now), 0.0001)
|
||||||
|
assertEquals(1.15, policy.calculateCommunityCreatorNewBoost(now.minusDays(10), now), 0.0001)
|
||||||
|
assertEquals(1.10, policy.calculateCommunityCreatorNewBoost(now.minusDays(11), now), 0.0001)
|
||||||
|
assertEquals(1.10, policy.calculateCommunityCreatorNewBoost(now.minusDays(20), now), 0.0001)
|
||||||
|
assertEquals(1.05, policy.calculateCommunityCreatorNewBoost(now.minusDays(21), now), 0.0001)
|
||||||
|
assertEquals(1.05, policy.calculateCommunityCreatorNewBoost(now.minusDays(30), now), 0.0001)
|
||||||
|
assertEquals(1.0, policy.calculateCommunityCreatorNewBoost(now.minusDays(31), now), 0.0001)
|
||||||
|
|
||||||
|
assertEquals(1.5, policy.calculateCreatorNewBoost(now.minusDays(10), now), 0.0001)
|
||||||
|
assertEquals(1.3, policy.calculateCreatorNewBoost(now.minusDays(20), now), 0.0001)
|
||||||
|
assertEquals(1.2, policy.calculateCreatorNewBoost(now.minusDays(30), now), 0.0001)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -17,4 +17,14 @@ class RecommendationSnapshotWindowPolicyTest {
|
|||||||
assertEquals(LocalDateTime.of(2026, 7, 9, 15, 0, 0), window.endExclusiveUtc)
|
assertEquals(LocalDateTime.of(2026, 7, 9, 15, 0, 0), window.endExclusiveUtc)
|
||||||
assertEquals(LocalDateTime.of(2026, 7, 9, 14, 59, 59), window.snapshotAt)
|
assertEquals(LocalDateTime.of(2026, 7, 9, 14, 59, 59), window.snapshotAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("KST 전날을 포함한 최근 7일을 UTC 조회 범위로 변환한다")
|
||||||
|
fun shouldConvertPreviousKstSevenDaysToUtcWindow() {
|
||||||
|
val window = policy.previousKstSevenDayUtcWindow(LocalDateTime.of(2026, 7, 10, 3, 0, 0))
|
||||||
|
|
||||||
|
assertEquals(LocalDateTime.of(2026, 7, 2, 15, 0, 0), window.startUtc)
|
||||||
|
assertEquals(LocalDateTime.of(2026, 7, 9, 15, 0, 0), window.endExclusiveUtc)
|
||||||
|
assertEquals(LocalDateTime.of(2026, 7, 9, 14, 59, 59), window.snapshotAt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user