docs(home): 인기 커뮤니티 스냅샷 산식을 문서화한다
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
## 3. Goals
|
||||
- `POPULAR_COMMUNITY` 스냅샷은 최근 7일 데이터를 기반으로 생성한다.
|
||||
- 인기 커뮤니티 점수 산식을 `((좋아요 수 * 0.50) + (댓글 수 * 0.40) + (크리에이터 팔로우 수 * 0.10)) * 신규 부스트`로 변경한다.
|
||||
- 인기 커뮤니티 점수 산식을 `((좋아요 수 * 0.50) + (댓글 수 * 0.50)) * 신규 부스트`로 변경한다.
|
||||
- 신규 부스트는 크리에이터 데뷔일 기준 10일 이내 1.15, 20일 이내 1.10, 30일 이내 1.05, 그 외 1.0을 적용한다.
|
||||
- 공지/고정 게시글과 유료 게시글은 스냅샷 후보와 조회 결과에서 제외한다.
|
||||
- 스케줄러 refresh와 fallback refresh는 동일한 `POPULAR_COMMUNITY` refresh 로직을 재사용한다.
|
||||
@@ -58,23 +58,20 @@
|
||||
|
||||
#### Requirements
|
||||
- `POPULAR_COMMUNITY` 점수는 아래 산식으로 계산한다.
|
||||
- `score = ((likeCount * 0.50) + (commentCount * 0.40) + (creatorFollowerCount * 0.10)) * newBoost`
|
||||
- `score = ((likeCount * 0.50) + (commentCount * 0.50)) * newBoost`
|
||||
- `likeCount`는 집계 기간 안에 생성된 활성 좋아요 수다.
|
||||
- 좋아요 수는 `creator_community_like.is_active = true`인 row를 기준으로 `distinct id` 집계한다.
|
||||
- `commentCount`는 집계 기간 안에 생성된 활성 댓글 수다.
|
||||
- 댓글 수는 `creator_community_comment.is_active = true`인 row를 기준으로 `distinct id` 집계한다.
|
||||
- 댓글 불가 게시글은 댓글 row가 있어도 산식의 `commentCount`를 0으로 계산한다.
|
||||
- `creatorFollowerCount`는 스냅샷 생성 시점 기준 크리에이터의 활성 팔로워 총수다.
|
||||
- `creatorFollowerCount`는 최근 7일 신규 팔로우 수가 아니며, 스냅샷 생성 시점까지 활성 상태인 전체 팔로워 수를 의미한다.
|
||||
- 팔로워 수는 `creator_following.creator_id = creator_community.member_id`이고 `is_active = true`인 row를 기준으로 `distinct id` 집계한다.
|
||||
- 점수 산식 상수는 `RecommendationScoreSpec` 등 기존 점수 정책 위치에 모아 DB expression과 Kotlin 정책 테스트가 같은 값을 참조하도록 한다.
|
||||
- 스냅샷 정렬은 점수 내림차순, 동점이면 스냅샷 생성 시 저장한 `randomTieBreaker` 오름차순을 유지한다.
|
||||
- 최종 저장 수는 기존 홈 노출 안정성을 위해 `POPULAR_COMMUNITY` 최대 20개를 유지한다.
|
||||
|
||||
#### Edge Cases
|
||||
- `likeCount`, `commentCount`, `creatorFollowerCount`가 모두 0인 게시글은 스냅샷 후보에서 제외한다.
|
||||
- 좋아요는 없지만 댓글 또는 팔로워 수가 있으면 산식에 따라 점수를 계산한다.
|
||||
- 댓글은 없지만 좋아요 또는 팔로워 수가 있으면 산식에 따라 점수를 계산한다.
|
||||
- `likeCount`, 산식에 반영 가능한 `commentCount`가 모두 0인 게시글은 스냅샷 후보에서 제외한다.
|
||||
- 좋아요는 없지만 산식에 반영 가능한 댓글 수가 있으면 산식에 따라 점수를 계산한다.
|
||||
- 댓글은 없지만 좋아요 수가 있으면 산식에 따라 점수를 계산한다.
|
||||
- 비활성 좋아요, 비활성 댓글, 비활성 게시글, 비활성 크리에이터는 집계에서 제외한다.
|
||||
- 스냅샷에는 존재하지만 조회 시점에 게시글 또는 크리에이터가 비활성화된 경우 응답에서 제외한다.
|
||||
|
||||
@@ -89,7 +86,7 @@
|
||||
- 기존 코드에 남아 있는 `created_at <= :snapshotAt` 방식은 이번 범위에서 half-open end-exclusive 조건으로 맞춘다.
|
||||
|
||||
#### Edge Cases
|
||||
- 집계 기간에 좋아요/댓글 데이터가 없어도 팔로워 수만으로 추천 후보가 될 수 있다.
|
||||
- 집계 기간에 좋아요와 산식에 반영 가능한 댓글 데이터가 모두 없으면 추천 후보가 될 수 없다.
|
||||
- 집계 기간과 무관하게 게시글 자체는 스냅샷 대상 시점 이전에 생성된 활성 무료/비공지 게시글이어야 한다.
|
||||
- 같은 `sectionType`, `snapshotAt`에 대해 재실행하면 기존 스냅샷을 대체하는 정책을 유지한다.
|
||||
|
||||
@@ -222,7 +219,7 @@
|
||||
- `POPULAR_COMMUNITY` 스냅샷 최종 저장 수
|
||||
- fallback refresh 실행/성공/실패/timeout 로그
|
||||
- fallback refresh lock 획득 성공/실패 로그
|
||||
- `likeCount`, `commentCount`, `creatorFollowerCount` 입력값 분포
|
||||
- `likeCount`, `commentCount` 입력값 분포
|
||||
- empty snapshot marker 저장 횟수
|
||||
- 홈 API `popularCommunityPosts` 빈 응답 비율
|
||||
- 홈 API fallback refresh 대기 시간
|
||||
@@ -237,7 +234,6 @@
|
||||
## 11. Decisions
|
||||
- 요구사항의 `is_pin`은 현재 코드의 `CreatorCommunity.isFixed` 및 DB 컬럼 `is_fixed`로 매핑한다.
|
||||
- 유료 게시글 제외는 `price > 0` 제외로 정의한다.
|
||||
- `creatorFollowerCount`는 스냅샷 생성 시점의 활성 팔로워 총수로 확정한다.
|
||||
- 일 단위 최신성을 강제하며, fallback 조건은 최신 스냅샷 부재가 아니라 대상일 `snapshotAt` 스냅샷 부재로 확정한다.
|
||||
- fallback 방식은 사용자 제안의 동일 refresh 로직 재사용, lock, double-check 원칙을 채택한다.
|
||||
- 더 나은 구현 방향은 기존 `RecommendationSnapshotFallbackService`에 `POPULAR_COMMUNITY`를 추가해 AI 캐릭터/응원 크리에이터와 같은 lock, timeout, single-flight 흐름을 공유하는 것이다.
|
||||
|
||||
Reference in New Issue
Block a user