fix: 동네 유저 추천 성능 개선 - 바운딩 박스 쿼리 및 위치 인덱스 추가#234
Conversation
- findAllWithLocation() 전체 조회 대신 바운딩 박스(BETWEEN) 쿼리로 DB 레벨 필터링 - Member 엔티티에 (latitude, longitude) 복합 인덱스 추가 - PriorityQueue 제거 후 stream sorted + limit(10) 으로 단순화 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Walkthrough
Changes지역 기반 추천 최적화
Sequence DiagramsequenceDiagram
participant Client
participant RecommendationService
participant MemberRepository
participant Database
participant DistanceCalculator
Client->>RecommendationService: recommendLocalMembers(memberId)
activate RecommendationService
Note over RecommendationService: 현재 멤버의 위도/경도 확인
alt 위치 정보 없음
RecommendationService-->>Client: 빈 리스트 반환
else 위치 정보 있음
Note over RecommendationService: 1km 경계상자 계산<br/>(minLat, maxLat, minLon, maxLon)
RecommendationService->>MemberRepository: findMembersInBoundingBox(bounds)
activate MemberRepository
MemberRepository->>Database: SELECT * FROM members<br/>WHERE lat BETWEEN ? AND ?<br/>AND lon BETWEEN ? AND ?
activate Database
Database-->>MemberRepository: 경계상자 내 멤버 목록 반환
deactivate Database
MemberRepository-->>RecommendationService: 필터링된 멤버 리스트
deactivate MemberRepository
Note over RecommendationService: 각 후보 멤버에 대해:<br/>- 요청 멤버 제외<br/>- 하버사인 거리 계산
loop 후보 멤버 순회
RecommendationService->>DistanceCalculator: calculateDistance(currentLat, currentLon,<br/>candidateLat, candidateLon)
activate DistanceCalculator
DistanceCalculator-->>RecommendationService: distanceKm
deactivate DistanceCalculator
end
Note over RecommendationService: 거리 기준 정렬 후<br/>상위 10명 선택
RecommendationService-->>Client: 상위 10명의 추천 멤버 반환
end
deactivate RecommendationService
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 60 minutes.Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
member/src/main/java/kr/co/readingtown/member/service/RecommendationService.java (1)
142-155:⚠️ Potential issue | 🟠 Major | ⚡ Quick win바운딩 박스만으로는 1km 반경이 보장되지 않습니다.
지금 구현은 사각형 후보군만 줄이고 끝나서, 박스 모서리에 있는 1km 초과 회원도 그대로 추천될 수 있습니다. Haversine 계산 뒤에
distance <= RADIUS_KM필터를 한 번 더 적용해야 반경 1km 요구사항이 맞습니다.수정 예시
List<LocalMemberRecommendationDto> result = allMembers.stream() .filter(member -> !member.getMemberId().equals(memberId)) .map(member -> { double distance = calculateDistance( currentLat, currentLon, member.getLatitude().doubleValue(), member.getLongitude().doubleValue() ); return LocalMemberRecommendationDto.from(member, distance); }) + .filter(dto -> dto.distanceKm() <= RADIUS_KM) .sorted(Comparator.comparing(LocalMemberRecommendationDto::distanceKm)) .limit(10) .collect(Collectors.toList());🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@member/src/main/java/kr/co/readingtown/member/service/RecommendationService.java` around lines 142 - 155, The current stream builds LocalMemberRecommendationDto using calculateDistance but never enforces the 1km radius, so members beyond RADIUS_KM can slip through; after mapping to LocalMemberRecommendationDto (or immediately after computing distance) add a filter that keeps only entries where the computed distance <= RADIUS_KM (use LocalMemberRecommendationDto.distanceKm() or the local distance variable) before sorting and limiting, ensuring RecommendationService's radius check is enforced.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@member/src/main/java/kr/co/readingtown/member/repository/MemberRepository.java`:
- Around line 45-56: The JPQL query in MemberRepository.findMembersInBoundingBox
is missing the onboarding filter so un-onboarded users are included; update the
query in the findMembersInBoundingBox method to include the condition
m.isOnboarded = true (i.e., add "AND m.isOnboarded = true" to the WHERE clause)
so it matches the previous findAllWithLocation behavior and still returns
List<Member> without adding new parameters.
---
Outside diff comments:
In
`@member/src/main/java/kr/co/readingtown/member/service/RecommendationService.java`:
- Around line 142-155: The current stream builds LocalMemberRecommendationDto
using calculateDistance but never enforces the 1km radius, so members beyond
RADIUS_KM can slip through; after mapping to LocalMemberRecommendationDto (or
immediately after computing distance) add a filter that keeps only entries where
the computed distance <= RADIUS_KM (use
LocalMemberRecommendationDto.distanceKm() or the local distance variable) before
sorting and limiting, ensuring RecommendationService's radius check is enforced.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7295e964-bf8e-4b19-b8fa-d143162af816
📒 Files selected for processing (3)
member/src/main/java/kr/co/readingtown/member/domain/Member.javamember/src/main/java/kr/co/readingtown/member/repository/MemberRepository.javamember/src/main/java/kr/co/readingtown/member/service/RecommendationService.java
| @Query(""" | ||
| SELECT m | ||
| FROM Member m | ||
| WHERE m.latitude BETWEEN :minLat AND :maxLat | ||
| AND m.longitude BETWEEN :minLon AND :maxLon | ||
| """) | ||
| List<Member> findMembersInBoundingBox( | ||
| @Param("minLat") BigDecimal minLat, | ||
| @Param("maxLat") BigDecimal maxLat, | ||
| @Param("minLon") BigDecimal minLon, | ||
| @Param("maxLon") BigDecimal maxLon | ||
| ); |
There was a problem hiding this comment.
isOnboarded 조건이 빠져 추천 대상이 넓어졌습니다.
이 메서드는 기존 findAllWithLocation() 경로를 대체해서 쓰이는데, 이전 쿼리에 있던 m.isOnboarded = true 가 빠져 아직 온보딩되지 않은 회원도 추천 후보에 포함될 수 있습니다. 기존 동작을 유지하려면 같은 필터를 여기에도 넣어야 합니다.
수정 예시
`@Query`("""
SELECT m
FROM Member m
WHERE m.latitude BETWEEN :minLat AND :maxLat
AND m.longitude BETWEEN :minLon AND :maxLon
+ AND m.isOnboarded = true
""")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@member/src/main/java/kr/co/readingtown/member/repository/MemberRepository.java`
around lines 45 - 56, The JPQL query in
MemberRepository.findMembersInBoundingBox is missing the onboarding filter so
un-onboarded users are included; update the query in the
findMembersInBoundingBox method to include the condition m.isOnboarded = true
(i.e., add "AND m.isOnboarded = true" to the WHERE clause) so it matches the
previous findAllWithLocation behavior and still returns List<Member> without
adding new parameters.
✨ Issue Number
📄 작업 내용 (주요 변경 사항)
Summary
findAllWithLocation()으로 위치 정보가 있는 전체 멤버를 조회하던 방식을 바운딩 박스 쿼리로 교체하여 DB 레벨에서 1km반경 후보만 필터링
Member엔티티에(latitude, longitude)복합 인덱스(idx_member_location) 추가Changes
RecommendationService: Haversine 거리 계산 전 바운딩 박스로 1차 필터링MemberRepository:findMembersInBoundingBox()쿼리 추가Member:@Table에(latitude, longitude)복합 인덱스 추가💬 리뷰 요구사항
Summary by CodeRabbit
릴리스 노트