feat(home): 크리에이터 랭킹 점수 정책을 변경한다

This commit is contained in:
2026-07-10 14:42:25 +09:00
parent 9c67e870f6
commit c7b6d0d7c5
4 changed files with 124 additions and 111 deletions

View File

@@ -0,0 +1,42 @@
package kr.co.vividnext.sodalive.v2.ranking.domain
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import java.time.LocalDateTime
data class CreatorRankingScoreDetail(
val scorePolicyVersion: String = CreatorRankingScoreSpec.SCORE_POLICY_VERSION,
val formula: String = CreatorRankingScoreSpec.FORMULA,
val metrics: Metrics,
val tieBreakers: TieBreakers
) {
fun toJson(): String = objectMapper.writeValueAsString(this)
data class Metrics(
val liveRevenue: Metric,
val contentRevenue: Metric,
val followIncrease: Metric,
val aiChat: Metric
)
data class Metric(
val rawValue: Long,
val rank: Int,
val rankScore: Double,
val weight: Double,
val weightedScore: Double
)
data class TieBreakers(
val creatorDebutAt: LocalDateTime?,
val creatorId: Long
)
companion object {
private val objectMapper: ObjectMapper = jacksonObjectMapper()
.registerModule(JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
}
}

View File

@@ -1,49 +1,24 @@
package kr.co.vividnext.sodalive.v2.ranking.domain
class CreatorRankingScorePolicy {
fun calculateContentLiveScore(
liveCanAmount: Long,
contentPurchaseCanAmount: Long
): Double {
return (liveCanAmount * CreatorRankingScoreSpec.CONTENT_LIVE_CAN_WEIGHT) +
(contentPurchaseCanAmount * CreatorRankingScoreSpec.CONTENT_PURCHASE_CAN_WEIGHT)
fun calculateRankScore(rawValue: Long, rank: Int): Double {
if (rawValue <= 0L) return 0.0
return (100 - (5 * (rank - 1))).coerceAtLeast(0).toDouble()
}
fun calculateEngagementScore(
contentLikeCount: Long,
contentCommentCount: Long
): Double {
return (contentLikeCount * CreatorRankingScoreSpec.CONTENT_LIKE_COUNT_WEIGHT) +
(contentCommentCount * CreatorRankingScoreSpec.CONTENT_COMMENT_COUNT_WEIGHT)
}
fun calculateSupportScore(
channelDonationCanAmount: Long,
channelDonationCount: Long,
fanTalkCount: Long
): Double {
return (channelDonationCanAmount * CreatorRankingScoreSpec.CHANNEL_DONATION_CAN_WEIGHT) +
(channelDonationCount * CreatorRankingScoreSpec.CHANNEL_DONATION_COUNT_WEIGHT) +
(fanTalkCount * CreatorRankingScoreSpec.FAN_TALK_COUNT_WEIGHT)
}
fun calculateFanLoyaltyScore(
finalFollowerCount: Long,
followIncrease: Long
): Double {
return (finalFollowerCount * CreatorRankingScoreSpec.FINAL_FOLLOWER_COUNT_WEIGHT) +
(followIncrease * CreatorRankingScoreSpec.FOLLOW_INCREASE_WEIGHT)
fun normalizeFollowIncrease(value: Long): Long {
return value.coerceAtLeast(0L)
}
fun calculateFinalScore(
contentLiveScore: Double,
engagementScore: Double,
supportScore: Double,
fanLoyaltyScore: Double
liveRevenueRankScore: Double,
contentRevenueRankScore: Double,
followIncreaseRankScore: Double,
aiChatRankScore: Double
): Double {
return (contentLiveScore * CreatorRankingScoreSpec.CONTENT_LIVE_SCORE_WEIGHT) +
(engagementScore * CreatorRankingScoreSpec.ENGAGEMENT_SCORE_WEIGHT) +
(supportScore * CreatorRankingScoreSpec.SUPPORT_SCORE_WEIGHT) +
(fanLoyaltyScore * CreatorRankingScoreSpec.FAN_LOYALTY_SCORE_WEIGHT)
return (liveRevenueRankScore * CreatorRankingScoreSpec.LIVE_REVENUE_WEIGHT) +
(contentRevenueRankScore * CreatorRankingScoreSpec.CONTENT_REVENUE_WEIGHT) +
(followIncreaseRankScore * CreatorRankingScoreSpec.FOLLOW_INCREASE_WEIGHT) +
(aiChatRankScore * CreatorRankingScoreSpec.AI_CHAT_WEIGHT)
}
}

View File

@@ -1,21 +1,12 @@
package kr.co.vividnext.sodalive.v2.ranking.domain
object CreatorRankingScoreSpec {
const val CONTENT_LIVE_CAN_WEIGHT = 0.7
const val CONTENT_PURCHASE_CAN_WEIGHT = 0.3
const val SCORE_POLICY_VERSION = "CREATOR_WEEKLY_POPULARITY_V2"
const val FORMULA = "liveRevenueRankScore * 0.6 + contentRevenueRankScore * 0.2 + " +
"followIncreaseRankScore * 0.1 + aiChatRankScore * 0.1"
const val CONTENT_LIKE_COUNT_WEIGHT = 0.5
const val CONTENT_COMMENT_COUNT_WEIGHT = 0.5
const val CHANNEL_DONATION_CAN_WEIGHT = 0.6
const val CHANNEL_DONATION_COUNT_WEIGHT = 0.2
const val FAN_TALK_COUNT_WEIGHT = 0.2
const val FINAL_FOLLOWER_COUNT_WEIGHT = 0.7
const val FOLLOW_INCREASE_WEIGHT = 0.3
const val CONTENT_LIVE_SCORE_WEIGHT = 0.35
const val ENGAGEMENT_SCORE_WEIGHT = 0.3
const val SUPPORT_SCORE_WEIGHT = 0.25
const val FAN_LOYALTY_SCORE_WEIGHT = 0.1
const val LIVE_REVENUE_WEIGHT = 0.6
const val CONTENT_REVENUE_WEIGHT = 0.2
const val FOLLOW_INCREASE_WEIGHT = 0.1
const val AI_CHAT_WEIGHT = 0.1
}