feat(home): 크리에이터 랭킹 스냅샷 저장 구조를 변경한다

This commit is contained in:
2026-07-10 14:43:11 +09:00
parent e596cb0826
commit 247569ee16
5 changed files with 258 additions and 352 deletions

View File

@@ -34,45 +34,15 @@ class CreatorRankingSnapshot(
@Column(name = "profile_image_url", updatable = false, length = 500)
val profileImageUrl: String?,
@Column(name = "rank_no", nullable = false, updatable = false)
val rankNo: Int,
@Column(name = "final_score", nullable = false, updatable = false)
val finalScore: Double,
@Column(name = "content_live_score", nullable = false, updatable = false)
val contentLiveScore: Double,
@Column(name = "score_policy_version", nullable = false, updatable = false, length = 80)
val scorePolicyVersion: String,
@Column(name = "engagement_score", nullable = false, updatable = false)
val engagementScore: Double,
@Column(name = "support_score", nullable = false, updatable = false)
val supportScore: Double,
@Column(name = "fan_loyalty_score", nullable = false, updatable = false)
val fanLoyaltyScore: Double,
@Column(name = "live_can_amount", nullable = false, updatable = false)
val liveCanAmount: Long,
@Column(name = "content_purchase_can_amount", nullable = false, updatable = false)
val contentPurchaseCanAmount: Long,
@Column(name = "content_like_count", nullable = false, updatable = false)
val contentLikeCount: Long,
@Column(name = "content_comment_count", nullable = false, updatable = false)
val contentCommentCount: Long,
@Column(name = "channel_donation_can_amount", nullable = false, updatable = false)
val channelDonationCanAmount: Long,
@Column(name = "channel_donation_count", nullable = false, updatable = false)
val channelDonationCount: Long,
@Column(name = "fan_talk_count", nullable = false, updatable = false)
val fanTalkCount: Long,
@Column(name = "final_follower_count", nullable = false, updatable = false)
val finalFollowerCount: Long,
@Column(name = "follow_increase", nullable = false, updatable = false)
val followIncrease: Long
@Column(name = "score_detail_json", nullable = false, updatable = false, columnDefinition = "json")
val scoreDetailJson: String
) : BaseEntity()

View File

@@ -7,7 +7,7 @@ import org.springframework.data.repository.query.Param
import java.time.LocalDateTime
interface CreatorRankingSnapshotRepository : JpaRepository<CreatorRankingSnapshot, Long> {
fun findAllByAggregationStartAtUtcAndAggregationEndAtUtcOrderByFinalScoreDesc(
fun findAllByAggregationStartAtUtcAndAggregationEndAtUtcOrderByRankNoAsc(
aggregationStartAtUtc: LocalDateTime,
aggregationEndAtUtc: LocalDateTime
): List<CreatorRankingSnapshot>
@@ -20,7 +20,7 @@ interface CreatorRankingSnapshotRepository : JpaRepository<CreatorRankingSnapsho
select max(latest.aggregation_end_at_utc)
from creator_ranking_snapshot latest
)
order by crs.final_score desc
order by crs.rank_no asc
""",
nativeQuery = true
)
@@ -38,7 +38,7 @@ interface CreatorRankingSnapshotRepository : JpaRepository<CreatorRankingSnapsho
from creator_ranking_snapshot latest
)
)
order by crs.final_score desc
order by crs.rank_no asc
""",
nativeQuery = true
)
@@ -55,7 +55,7 @@ interface CreatorRankingSnapshotRepository : JpaRepository<CreatorRankingSnapsho
where latest.ranking_type = :rankingType
and latest.visible_from_at <= :nowUtc
)
order by crs.final_score desc
order by crs.rank_no asc
""",
nativeQuery = true
)
@@ -69,6 +69,7 @@ interface CreatorRankingSnapshotRepository : JpaRepository<CreatorRankingSnapsho
select *
from creator_ranking_snapshot crs
where crs.ranking_type = :rankingType
and crs.visible_from_at <= :nowUtc
and crs.aggregation_start_at_utc = (
select max(previous.aggregation_start_at_utc)
from creator_ranking_snapshot previous
@@ -76,7 +77,7 @@ interface CreatorRankingSnapshotRepository : JpaRepository<CreatorRankingSnapsho
and previous.aggregation_start_at_utc < :currentAggregationStartAtUtc
and previous.visible_from_at <= :nowUtc
)
order by crs.final_score desc
order by crs.rank_no asc
""",
nativeQuery = true
)

View File

@@ -15,7 +15,7 @@ class DefaultCreatorRankingSnapshotRepository(
aggregationStartAtUtc: LocalDateTime,
aggregationEndAtUtc: LocalDateTime
): List<CreatorRankingSnapshotRecord> {
return repository.findAllByAggregationStartAtUtcAndAggregationEndAtUtcOrderByFinalScoreDesc(
return repository.findAllByAggregationStartAtUtcAndAggregationEndAtUtcOrderByRankNoAsc(
aggregationStartAtUtc = aggregationStartAtUtc,
aggregationEndAtUtc = aggregationEndAtUtc
).map { it.toRecord() }
@@ -42,16 +42,12 @@ class DefaultCreatorRankingSnapshotRepository(
nowUtc: LocalDateTime
): List<CreatorRankingSnapshotRecord> {
return repository.findPreviousVisibleSnapshots(
rankingType = rankingType.name,
currentAggregationStartAtUtc = currentAggregationStartAtUtc,
nowUtc = nowUtc
rankingType.name,
currentAggregationStartAtUtc,
nowUtc
).map { it.toRecord() }
}
override fun isSnapshotTableEmpty(): Boolean {
return repository.count() == 0L
}
@Transactional
override fun replaceSnapshots(
rankingType: CreatorRankingType,
@@ -61,9 +57,9 @@ class DefaultCreatorRankingSnapshotRepository(
newSnapshots: List<CreatorRankingSnapshotRecord>
) {
repository.deleteByRankingTypeAndAggregationStartAtUtcAndAggregationEndAtUtc(
rankingType = rankingType,
aggregationStartAtUtc = aggregationStartAtUtc,
aggregationEndAtUtc = aggregationEndAtUtc
rankingType,
aggregationStartAtUtc,
aggregationEndAtUtc
)
repository.saveAll(newSnapshots.map { it.toEntity(rankingType, visibleFromAtUtc) })
}
@@ -77,20 +73,10 @@ class DefaultCreatorRankingSnapshotRepository(
creatorId = creatorId,
nickname = nickname,
profileImageUrl = profileImageUrl,
rankNo = rankNo,
finalScore = finalScore,
contentLiveScore = contentLiveScore,
engagementScore = engagementScore,
supportScore = supportScore,
fanLoyaltyScore = fanLoyaltyScore,
liveCanAmount = liveCanAmount,
contentPurchaseCanAmount = contentPurchaseCanAmount,
contentLikeCount = contentLikeCount,
contentCommentCount = contentCommentCount,
channelDonationCanAmount = channelDonationCanAmount,
channelDonationCount = channelDonationCount,
fanTalkCount = fanTalkCount,
finalFollowerCount = finalFollowerCount,
followIncrease = followIncrease
scorePolicyVersion = scorePolicyVersion,
scoreDetailJson = scoreDetailJson
)
}
@@ -106,20 +92,10 @@ class DefaultCreatorRankingSnapshotRepository(
creatorId = creatorId,
nickname = nickname,
profileImageUrl = profileImageUrl,
rankNo = rankNo,
finalScore = finalScore,
contentLiveScore = contentLiveScore,
engagementScore = engagementScore,
supportScore = supportScore,
fanLoyaltyScore = fanLoyaltyScore,
liveCanAmount = liveCanAmount,
contentPurchaseCanAmount = contentPurchaseCanAmount,
contentLikeCount = contentLikeCount,
contentCommentCount = contentCommentCount,
channelDonationCanAmount = channelDonationCanAmount,
channelDonationCount = channelDonationCount,
fanTalkCount = fanTalkCount,
finalFollowerCount = finalFollowerCount,
followIncrease = followIncrease
scorePolicyVersion = scorePolicyVersion,
scoreDetailJson = scoreDetailJson
)
}
}

View File

@@ -24,8 +24,6 @@ interface CreatorRankingSnapshotPort {
nowUtc: LocalDateTime
): List<CreatorRankingSnapshotRecord>
fun isSnapshotTableEmpty(): Boolean
fun replaceSnapshots(
rankingType: CreatorRankingType,
aggregationStartAtUtc: LocalDateTime,
@@ -43,18 +41,8 @@ data class CreatorRankingSnapshotRecord(
val creatorId: Long,
val nickname: String,
val profileImageUrl: String?,
val rankNo: Int,
val finalScore: Double,
val contentLiveScore: Double,
val engagementScore: Double,
val supportScore: Double,
val fanLoyaltyScore: Double,
val liveCanAmount: Long,
val contentPurchaseCanAmount: Long,
val contentLikeCount: Long,
val contentCommentCount: Long,
val channelDonationCanAmount: Long,
val channelDonationCount: Long,
val fanTalkCount: Long,
val finalFollowerCount: Long,
val followIncrease: Long
val scorePolicyVersion: String,
val scoreDetailJson: String
)