Skip to content

[feat] 데이트 코스 생성 알고리즘 개선 (하드 룰 → 소프트 룰)#8

Merged
1000hyehyang merged 3 commits into
devfrom
feat/7-datecourse-AL-modi
Jun 13, 2026
Merged

[feat] 데이트 코스 생성 알고리즘 개선 (하드 룰 → 소프트 룰)#8
1000hyehyang merged 3 commits into
devfrom
feat/7-datecourse-AL-modi

Conversation

@HHS-kor

@HHS-kor HHS-kor commented Jun 10, 2026

Copy link
Copy Markdown
Member

✨ 무엇을 바꿨나요?

데이트 코스 생성 시 코스 간 장소 중복을 완전 제외(하드 룰)하던 방식을 **점수 패널티(소프트 룰)**로 전환하고, 최고점 장소를 고정 선택하던 방식을 **점수 기반 확률 선택(Weighted Random)**으로 개선했습니다.

🔗 관련 이슈

Closes #7

💡 왜 바꿨나요?

기존 방식은 GENERAL → TRENDY → POPULAR 순서로 코스를 생성하면서 이전 코스에서 사용한 장소를 다음 코스에서 완전히 제외했다. 장소 수가 부족할 경우 후순위로 생성되는 코스가 채울 후보가 없어 슬롯이 잘리거나 코스 생성 자체가 실패하는 문제가 있었다. 또한 항상 최고점 장소만 고정 선택되어 동일한 요청에 대해 매번 똑같은 코스가 생성되는 한계가 있었다.

📝 주요 변경 사항

  • CourseSelector: Set globallyUsedIds(코스 간 하드 제외) → Map<Long, Integer> usageCounts(사용 횟수) 로 교체. 코스 간 제외 필터 제거, .max() 고정 선택 → Weighted Random Selection 도입
    • 패널티 배수: 0회 ×1.0 / 1회 ×0.6 / 2회 ×0.3 / 3회 ×0.15 …
    • Sharpness(=2.0): 점수 차를 확률에 반영하는 강도 튜닝 상수 — 최고점 장소가 대체로 우세하되 다양성 확보
    • 코스 내부 장소 중복 금지(pickedIds)는 유지
  • DateCourseGenerationService: usageCounts 맵 + batchSignatures Set 도입
    • 코스 커밋 후 picked 장소의 usageCounts 증가 → 다음 모드에 패널티 반영
    • 같은 배치 안에서 "코스 전체가 동일"하게 나오면 최대 5회 재추첨, 실패 시 허용하여 생성 보장
  • CourseSelectorTest: 하드 제외 검증 테스트 제거, 중복 허용·패널티 확률·선택 다양성 검증으로 교체
  • CourseDiversityMetricsTest (신규): 발표용 정량 지표 측정 — 생성 성공률·코스 간 중복률·평균 고유 장소 수
  • scripts/seed-local-scarce.sql (신규): 장소 부족 시나리오(FOOD 2 / CAFE 1 / ACTIVITY 1) 시연용 시드

👀 리뷰어가 보면 좋은 부분

  • CourseSelector.weightedPick(): 모든 가중치가 0 이하인 경우(점수가 음수가 될 수 없지만 방어 처리) 균등 확률로 폴백하는 엣지 케이스 처리가 적절한지
  • SELECTION_SHARPNESS = 2.0, crossCoursePenalty 배수(0.6, 0.5): 현재는 상수로 고정. 추후 설정값으로 외부화가 필요할지 여부
  • MAX_REROLL = 5: 재추첨 상한이 성능에 미치는 영향 — Weighted Random이라 매 시도마다 다른 결과가 나와 실제 루프 횟수는 대부분 1~2회에 그침
  • CourseScorer는 변경 없음: 점수식(0.6×거리 + 0.4×모드가중치)은 그대로 두고 패널티·sharpening을 CourseSelector 선택 정책으로 분리한 설계 의도

🧪 테스트

방식 (해당하는 것만 체크)

  • 로컬 환경에서 확인
  • 운영 환경에서 확인
  • 단위 / 통합 테스트
  • 해당 없음

메모 (시나리오, 커맨드, 스크린샷 링크 등 — 선택)

  • 시나리오 1 — 부족 풀(FOOD 2/CAFE 1/ACT 1), [FOOD, CAFE, ACTIVITY] 3슬롯 코스 생성
    • 결과: GENERAL/TRENDY/POPULAR 3코스 모두 skippedSlotIndices: [] — 기존 방식이라면 2·3번째 코스의 CAFE·ACTIVITY 슬롯이 잘렸을 상황에서 정상 생성 확인
  • 시나리오 2 — 풍부 풀(FOOD 5/CAFE 3/ACT 3), 동일 요청 3회 반복
    • 결과: 호출마다 코스 구성이 달라짐 (Weighted Random 동작 확인)
  • 시나리오 3 — 동일 카테고리+태그 슬롯 2개, 후보 1개
    • 결과: skippedSlotIndices: [1] — 두 번째 슬롯 skip, 코스 내부 중복 금지 유지 확인
  • 단위 테스트: CourseSelectorTest, CourseScorerTest 포함 전체 suite 통과
  • CourseDiversityMetricsTest 지표 출력 (부족 풀 200배치 시뮬레이션):
생성 성공률  : 100.0%
코스 간 중복률: 79.3%  (CAFE·ACT 후보 각 1개라 불가피)
평균 고유 장소: 3.93 / 4

- 코스 간 장소 중복 하드 제외 → 사용 횟수 기반 점수 패널티로 전환
  (0회 ×1.0 / 1회 ×0.6 / 2회 ×0.3 ...)
- 최고점 고정 선택 → 점수 기반 Weighted Random Selection (SHARPNESS=2.0)
- 코스 내부 장소 중복 금지는 유지
- 배치 내 동일 코스 출력 방지를 위한 제한적 재추첨(최대 5회) 추가
- CourseSelectorTest: 하드 제외 검증 → 중복 허용·패널티·확률 검증으로 교체
- CourseDiversityMetricsTest: 발표용 생성 성공률·중복률·고유 장소 수 측정 추가
- seed-local-scarce.sql: 장소 부족 시나리오(FOOD2/CAFE1/ACT1) 시연용 시드 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@HHS-kor

HHS-kor commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

일단 코스 새로고침 또는 새로운추천제공 기능은 구현하지 않음

@1000hyehyang 1000hyehyang merged commit 239d710 into dev Jun 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 데이트 코스 생성 알고리즘 개선

2 participants