fix(recommendation): 응원 크리에이터 후속 보완을 반영한다

This commit is contained in:
2026-07-31 14:22:59 +09:00
parent 5123494e0e
commit ed54483cab
8 changed files with 427 additions and 19 deletions

View File

@@ -26,6 +26,7 @@ import kr.co.vividnext.sodalive.member.MemberRole
import kr.co.vividnext.sodalive.member.QMember
import kr.co.vividnext.sodalive.member.QMember.member
import kr.co.vividnext.sodalive.member.block.QBlockMember
import kr.co.vividnext.sodalive.member.following.QCreatorFollowing
import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendationScoreSpec
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendedSectionType
@@ -587,8 +588,7 @@ class DefaultHomeRecommendationQueryRepository(
union all
select lr.member_id as creator_id, lr.begin_date_time as debut_at
from live_room lr
where lr.is_active = true
and lr.channel_name is not null
where lr.channel_name is not null
and lr.channel_name <> ''
and lr.begin_date_time <= :snapshotAt
) debut_events
@@ -816,7 +816,13 @@ class DefaultHomeRecommendationQueryRepository(
)
)
.from(member)
.where(member.isActive.isTrue, member.id.`in`(creatorIds), notBlockedCreatorCondition(memberId, member.id))
.where(
member.isActive.isTrue,
member.id.`in`(creatorIds),
notViewerCondition(memberId, member.id),
notActiveFollowedCreatorCondition(memberId, member.id),
notBlockedCreatorCondition(memberId, member.id)
)
.fetch()
}
@@ -1278,6 +1284,24 @@ class DefaultHomeRecommendationQueryRepository(
.notExists()
}
private fun notViewerCondition(memberId: Long?, creatorIdPath: Expression<Long>): BooleanExpression? {
return memberId?.let { Expressions.booleanTemplate("{0} <> {1}", creatorIdPath, it) }
}
private fun notActiveFollowedCreatorCondition(memberId: Long?, creatorIdPath: Expression<Long>): BooleanExpression? {
if (memberId == null) return null
val creatorFollowing = QCreatorFollowing("recommendationCreatorFollowing")
return JPAExpressions
.selectOne()
.from(creatorFollowing)
.where(
creatorFollowing.isActive.isTrue,
creatorFollowing.member.id.eq(memberId),
creatorFollowing.creator.id.eq(creatorIdPath)
)
.notExists()
}
private fun orderedCommunityPostCondition(memberId: Long?): BooleanExpression {
if (memberId == null) return Expressions.FALSE
return JPAExpressions

View File

@@ -92,24 +92,38 @@ open class RecommendationSnapshotRefreshService(
open fun refreshCheerCreatorSnapshots(nowUtc: LocalDateTime = LocalDateTime.now(ZoneOffset.UTC)): Int {
val startedAt = System.currentTimeMillis()
val window = windowPolicy.previousKstSevenDayUtcWindow(nowUtc)
val snapshots = queryPort.findCheerCreatorSnapshots(
window.startUtc,
window.endExclusiveUtc,
CHEER_CREATOR_SNAPSHOT_LIMIT
)
snapshotPort.replaceSnapshots(RecommendedSectionType.CHEER_CREATOR, window.snapshotAt, snapshots)
afterCommit {
log.info(
"event=cheer_creator_recommendation_snapshot_refresh_success " +
"snapshotAt={} windowStartUtc={} windowEndExclusiveUtc={} savedCount={} elapsedMs={}",
try {
val snapshots = queryPort.findCheerCreatorSnapshots(
window.startUtc,
window.endExclusiveUtc,
CHEER_CREATOR_SNAPSHOT_LIMIT
)
snapshotPort.replaceSnapshots(RecommendedSectionType.CHEER_CREATOR, window.snapshotAt, snapshots)
afterCommit {
log.info(
"event=cheer_creator_recommendation_snapshot_refresh_success " +
"snapshotAt={} windowStartUtc={} windowEndExclusiveUtc={} savedCount={} elapsedMs={}",
window.snapshotAt,
window.startUtc,
window.endExclusiveUtc,
snapshots.size,
System.currentTimeMillis() - startedAt
)
}
return snapshots.size
} catch (ex: Exception) {
log.warn(
"event=cheer_creator_recommendation_snapshot_refresh_failure " +
"snapshotAt={} windowStartUtc={} windowEndExclusiveUtc={} elapsedMs={} error={}",
window.snapshotAt,
window.startUtc,
window.endExclusiveUtc,
snapshots.size,
System.currentTimeMillis() - startedAt
System.currentTimeMillis() - startedAt,
ex.message,
ex
)
throw ex
}
return snapshots.size
}
@Transactional