feat(content-ranking): 랭킹 점수 정책을 추가한다
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user