feat(content-ranking): 랭킹 점수 정책을 추가한다

This commit is contained in:
2026-06-24 12:37:55 +09:00
parent dc93f9845b
commit e4706d6699
2 changed files with 302 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
package kr.co.vividnext.sodalive.v2.content.ranking.domain
import java.time.LocalDateTime
import java.time.temporal.ChronoUnit
import kotlin.math.max
class AudioRankingScorePolicy {
fun calculateWeeklyPopularScore(
revenue: Long,
salesCount: Long,
viewCount: Long,
likeCount: Long,
commentCount: Long,
isPaid: Boolean
): Double {
return if (isPaid) {
revenue * WEEKLY_PAID_REVENUE_WEIGHT +
salesCount * WEEKLY_PAID_SALES_COUNT_WEIGHT +
likeCount * WEEKLY_PAID_LIKE_COUNT_WEIGHT +
commentCount * WEEKLY_PAID_COMMENT_COUNT_WEIGHT
} else {
viewCount * WEEKLY_FREE_VIEW_COUNT_WEIGHT +
likeCount * WEEKLY_FREE_LIKE_COUNT_WEIGHT +
commentCount * WEEKLY_FREE_COMMENT_COUNT_WEIGHT
}
}
fun normalizeScore(currentScore: Double, maxScore: Double): Double {
if (maxScore <= 0.0) {
return 0.0
}
return currentScore / maxScore * 100.0
}
fun calculateRisingScore(
recentSalesCount: Long,
previousSalesCount: Long,
recentViewCount: Long,
previousViewCount: Long,
recentLikeCount: Long,
previousLikeCount: Long,
recentCommentCount: Long,
previousCommentCount: Long,
releaseDate: LocalDateTime,
aggregationEndAt: LocalDateTime,
isPaid: Boolean
): Double {
val salesGrowth = applyMinimumThreshold(
growthRate(recentSalesCount, previousSalesCount),
recentSalesCount,
RISING_SALES_COUNT_THRESHOLD
)
val viewGrowth = applyMinimumThreshold(
growthRate(recentViewCount, previousViewCount),
recentViewCount,
RISING_VIEW_COUNT_THRESHOLD
)
val likeGrowth = applyMinimumThreshold(
growthRate(recentLikeCount, previousLikeCount),
recentLikeCount,
RISING_LIKE_COUNT_THRESHOLD
)
val commentGrowth = applyMinimumThreshold(
growthRate(recentCommentCount, previousCommentCount),
recentCommentCount,
RISING_COMMENT_COUNT_THRESHOLD
)
val contentGrowthScore = if (isPaid) {
salesGrowth * RISING_PAID_SALES_GROWTH_WEIGHT +
viewGrowth * RISING_PAID_VIEW_GROWTH_WEIGHT
} else {
viewGrowth * RISING_FREE_VIEW_GROWTH_WEIGHT +
likeGrowth * RISING_FREE_LIKE_GROWTH_WEIGHT +
commentGrowth * RISING_FREE_COMMENT_GROWTH_WEIGHT
}
return (
contentGrowthScore * RISING_CONTENT_GROWTH_SCORE_WEIGHT +
likeGrowth * RISING_LIKE_GROWTH_WEIGHT +
commentGrowth * RISING_COMMENT_GROWTH_WEIGHT
) * releaseBoost(releaseDate, aggregationEndAt)
}
fun applyMinimumThreshold(growthRate: Double, recentCount: Long, minimumThreshold: Long): Double {
return if (recentCount < minimumThreshold) 0.0 else growthRate
}
fun releaseBoost(releaseDate: LocalDateTime, aggregationEndAt: LocalDateTime): Double {
val days = ChronoUnit.DAYS.between(releaseDate, aggregationEndAt).coerceAtLeast(0)
return when {
days <= 3 -> RELEASE_BOOST_WITHIN_THREE_DAYS
days <= 7 -> RELEASE_BOOST_WITHIN_SEVEN_DAYS
days <= 14 -> RELEASE_BOOST_WITHIN_FOURTEEN_DAYS
else -> RELEASE_BOOST_DEFAULT
}
}
private fun growthRate(recentCount: Long, previousCount: Long): Double {
return (recentCount - previousCount).toDouble() / max(previousCount, 1).toDouble()
}
companion object {
const val WEEKLY_PAID_REVENUE_WEIGHT = 0.45
const val WEEKLY_PAID_SALES_COUNT_WEIGHT = 0.35
const val WEEKLY_PAID_LIKE_COUNT_WEIGHT = 0.1
const val WEEKLY_PAID_COMMENT_COUNT_WEIGHT = 0.1
const val WEEKLY_FREE_VIEW_COUNT_WEIGHT = 0.5
const val WEEKLY_FREE_LIKE_COUNT_WEIGHT = 0.25
const val WEEKLY_FREE_COMMENT_COUNT_WEIGHT = 0.25
const val RISING_CONTENT_GROWTH_SCORE_WEIGHT = 0.5
const val RISING_LIKE_GROWTH_WEIGHT = 0.25
const val RISING_COMMENT_GROWTH_WEIGHT = 0.25
const val RISING_PAID_SALES_GROWTH_WEIGHT = 0.6
const val RISING_PAID_VIEW_GROWTH_WEIGHT = 0.4
const val RISING_FREE_VIEW_GROWTH_WEIGHT = 0.5
const val RISING_FREE_LIKE_GROWTH_WEIGHT = 0.25
const val RISING_FREE_COMMENT_GROWTH_WEIGHT = 0.25
const val RISING_VIEW_COUNT_THRESHOLD = 10L
const val RISING_LIKE_COUNT_THRESHOLD = 3L
const val RISING_COMMENT_COUNT_THRESHOLD = 3L
const val RISING_SALES_COUNT_THRESHOLD = 3L
const val RELEASE_BOOST_WITHIN_THREE_DAYS = 1.5
const val RELEASE_BOOST_WITHIN_SEVEN_DAYS = 1.3
const val RELEASE_BOOST_WITHIN_FOURTEEN_DAYS = 1.15
const val RELEASE_BOOST_DEFAULT = 1.0
}
}