Skip to content

fix: 동네 유저 추천 성능 개선 - 바운딩 박스 쿼리 및 위치 인덱스 추가#234

Open
choiseoji wants to merge 1 commit into
devfrom
fix/233-distance
Open

fix: 동네 유저 추천 성능 개선 - 바운딩 박스 쿼리 및 위치 인덱스 추가#234
choiseoji wants to merge 1 commit into
devfrom
fix/233-distance

Conversation

@choiseoji
Copy link
Copy Markdown
Member

@choiseoji choiseoji commented May 3, 2026

✨ Issue Number

close #233

📄 작업 내용 (주요 변경 사항)

Summary

  • 기존 findAllWithLocation()으로 위치 정보가 있는 전체 멤버를 조회하던 방식을 바운딩 박스 쿼리로 교체하여 DB 레벨에서 1km
    반경 후보만 필터링
  • Member 엔티티에 (latitude, longitude) 복합 인덱스(idx_member_location) 추가
  • 우선순위 큐 도입하려했으나, 애초에 바운딩 쿼리로 후보군이 줄었기 때문에 List sort가 더 적합!

Changes

  • RecommendationService: Haversine 거리 계산 전 바운딩 박스로 1차 필터링
  • MemberRepository: findMembersInBoundingBox() 쿼리 추가
  • Member: @Table(latitude, longitude) 복합 인덱스 추가

💬 리뷰 요구사항

Summary by CodeRabbit

릴리스 노트

  • 성능 개선
    • 주변 지역 회원 검색 및 추천 기능의 응답 속도가 향상되었습니다.
    • 위치 기반 데이터 조회 처리가 최적화되어 시스템 효율성이 개선되었습니다.
    • 지역별 회원 추천 기능이 더욱 빠르고 안정적으로 동작합니다.

- findAllWithLocation() 전체 조회 대신 바운딩 박스(BETWEEN) 쿼리로 DB 레벨 필터링
- Member 엔티티에 (latitude, longitude) 복합 인덱스 추가
- PriorityQueue 제거 후 stream sorted + limit(10) 으로 단순화

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@choiseoji choiseoji self-assigned this May 3, 2026
@choiseoji choiseoji added the 🛠️fix 기존 작성된 코드 수정 시 label May 3, 2026
@choiseoji choiseoji linked an issue May 3, 2026 that may be closed by this pull request
4 tasks
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

Walkthrough

Member 엔티티에 위도/경도 복합 인덱스를 추가하고, 새로운 경계상자 쿼리 메서드를 리포지토리에 추가하며, 추천 서비스가 1km 경계상자 사전 필터링을 통해 후보자를 먼저 좁힌 후 하버사인 거리 계산을 적용하도록 개선했습니다.

Changes

지역 기반 추천 최적화

레이어 / 파일 요약
데이터 베이스 인덱싱
member/src/main/java/kr/co/readingtown/member/domain/Member.java
@Table 애너테이션에 latitude, longitude 컬럼을 포함하는 복합 인덱스 idx_member_location을 명시적으로 선언합니다.
쿼리 레이어 확장
member/src/main/java/kr/co/readingtown/member/repository/MemberRepository.java
findMembersInBoundingBox(BigDecimal minLat, BigDecimal maxLat, BigDecimal minLon, BigDecimal maxLon) 메서드를 추가하여 위도/경도 범위 내의 멤버를 BETWEEN 조건으로 조회합니다. 기존 findAllWithLocation() 메서드는 유지됩니다.
비즈니스 로직 최적화
member/src/main/java/kr/co/readingtown/member/service/RecommendationService.java
recommendLocalMembers(Long memberId)가 현재 멤버의 좌표 주변 1km 경계상자를 계산한 후 리포지토리의 새로운 경계상자 쿼리로 후보군을 필터링하고, 축소된 후보군에만 하버사인 거리 계산과 상위 10명 선별을 적용합니다.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Feat/127 recommend members #132: 동일한 지역 기반 추천 기능을 다룹니다. 해당 PR에서 recommendLocalMembersfindAllWithLocation을 초기 구현했으며, 이번 PR에서는 서비스가 새로운 findMembersInBoundingBox 쿼리를 사용하도록 변경하고 멤버 엔티티에 DB 인덱스를 추가합니다.

Poem

🐰 효율의 길을 찾아
경계상자가 길을 밝혀
멀리서 먼저 거른 후
하버사인으로 거리 재어
열 명의 이웃이 반갑네요 🏘️✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 바운딩 박스 쿼리(#233의 1차 목표)와 복합 인덱스 추가는 완벽히 충족되었으나, Top-K PriorityQueue 구현(#233 요구사항 중 하나)은 제외되었습니다. Top-K PriorityQueue를 구현하거나, 이 결정에 대한 명확한 기술적 근거를 PR 설명에 추가하여 #233의 요구사항 충족을 명시하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 주요 변경사항인 바운딩 박스 쿼리 도입과 위치 인덱스 추가를 명확하게 설명하고 있으며, 변경사항과 직접적으로 관련되어 있습니다.
Description check ✅ Passed PR 설명은 템플릿 구조(이슈 번호, 작업 내용, 변경사항)를 따르고 있으며, 주요 변경사항이 명확하게 설명되어 있습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 동네 기반 사용자 추천 성능 개선(#233)과 관련된 범위 내에 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/233-distance

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.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5dd1a29 and 6f56855.

📒 Files selected for processing (3)
  • member/src/main/java/kr/co/readingtown/member/domain/Member.java
  • member/src/main/java/kr/co/readingtown/member/repository/MemberRepository.java
  • member/src/main/java/kr/co/readingtown/member/service/RecommendationService.java

Comment on lines +45 to +56
@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
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🛠️fix 기존 작성된 코드 수정 시

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🛠️fix : 동네 기반 유저 추천 개선

1 participant