Skip to content

Refactor : 근처 audio spot쿼리 개선#109

Merged
joonyee merged 3 commits intodevelopfrom
refactor/audio_spot
Sep 17, 2025
Merged

Refactor : 근처 audio spot쿼리 개선#109
joonyee merged 3 commits intodevelopfrom
refactor/audio_spot

Conversation

@joonyee
Copy link
Contributor

@joonyee joonyee commented Sep 17, 2025

Summary by CodeRabbit

  • Refactor
    • 주변 스팟 조회 시 오디오 가이드 유무 확인을 개별 쿼리에서 일괄 조회로 변경하여 지연시간 및 서버 부하 감소, 대량 요청에서 성능 향상.
  • Chores
    • 여러 콘텐츠 ID에 대해 오디오 가이드 존재 여부를 일괄로 조회할 수 있는 기능 추가로 사전 필터링 지원.
  • Breaking Change
    • NearbyAudioSpot 응답에서 "hashtag" 필드(타입 정보)가 제거되어 해당 JSON 속성이 더 이상 반환되지 않음.
  • Style
    • 응답 설정부의 불필요한 공백 정리.

@joonyee joonyee self-assigned this Sep 17, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 17, 2025

Walkthrough

AudioGuideRepository에 콘텐츠 ID 목록으로 오디오 가이드 존재 콘텐츠를 배치 조회하는 JPQL 메서드가 추가되었고, SpotServiceImpl.getNearbySpotsWithAudioGuides는 개별 exists 호출을 일괄 조회 후 Set으로 필터링하도록 변경되었다. NearbyAudioSpotResponse에서 type 필드가 제거되었다.

Changes

Cohort / File(s) Summary
Guide Repository
src/main/java/com/yfive/gbjs/domain/guide/repository/AudioGuideRepository.java
JPQL 기반 배치 조회 메서드 추가: findContentIdsWithAudioGuidesByContentIdIn(List<Long>)가 DISTINCT한 contentId 목록을 반환하도록 정의.
Spot Service
src/main/java/com/yfive/gbjs/domain/spot/service/SpotServiceImpl.java
per-spot existsByContentId 호출을 제거하고, 모든 스팟 ID를 수집해 한 번의 리포지토리 호출로 List<Long>을 받아 HashSet으로 변환한 뒤 contains로 필터링하도록 변경. 관련 컬렉션 import 추가 및 불필요한 .type(...) 설정 삭제.
DTO / Response
src/main/java/com/yfive/gbjs/domain/spot/dto/response/NearbyAudioSpotResponse.java
클래스에서 type 필드(@JsonProperty("hashtag")) 제거 — 해당 JSON 속성 삭제.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant SpotService as SpotServiceImpl
  participant SpotRepo as SpotRepository
  participant AudioRepo as AudioGuideRepository

  Client->>SpotService: getNearbySpotsWithAudioGuides(params)
  SpotService->>SpotRepo: findNearbySpots(params)
  SpotRepo-->>SpotService: List<Spot>
  SpotService->>SpotService: extract allSpotIds
  rect rgba(210,235,255,0.4)
    note over SpotService,AudioRepo: 배치 조회로 오디오 가이드 존재 콘텐츠 ID 가져오기
    SpotService->>AudioRepo: findContentIdsWithAudioGuidesByContentIdIn(allSpotIds)
    AudioRepo-->>SpotService: List<Long> contentIds
  end
  SpotService->>SpotService: Set<Long> ids = new HashSet<>(contentIds)
  SpotService->>SpotService: filter spots by ids.contains(spotId)
  SpotService-->>Client: Filtered SpotResponses
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

♻️ refactor

Poem

토끼가 폴짝, 쿼리 하나로 쓱—
ID 모아, Set에 쏙 넣고 확인 쓱쓱.
스팟은 정렬, 가이드는 표시,
당근 한 입에 코드도 가뿐히! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 제목 "Refactor : 근처 audio spot쿼리 개선"은 PR의 주된 변경점인 근처 오디오 스팟 쿼리 로직/성능 개선을 직관적으로 요약하고 있어 변경의 핵심을 잘 반영합니다. 문장이 짧고 스캔하기 쉬우며 파일 목록·이모지 등 불필요한 잡음이 없어 팀 히스토리에서 식별하기에 적절합니다. 다만 콜론 앞뒤 공백과 영어·한글 혼용("audio spot") 같은 스타일 일관성은 소소하게 개선할 여지가 있습니다.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/audio_spot

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e736de4 and 4feb455.

📒 Files selected for processing (2)
  • src/main/java/com/yfive/gbjs/domain/spot/dto/response/NearbyAudioSpotResponse.java (0 hunks)
  • src/main/java/com/yfive/gbjs/domain/spot/service/SpotServiceImpl.java (2 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/com/yfive/gbjs/domain/spot/dto/response/NearbyAudioSpotResponse.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/com/yfive/gbjs/domain/spot/service/SpotServiceImpl.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and Test

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

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

@github-actions
Copy link

github-actions bot commented Sep 17, 2025

Test Results

0 tests   0 ✅  0s ⏱️
0 suites  0 💤
0 files    0 ❌

Results for commit 4feb455.

♻️ This comment has been updated with latest results.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (3)
src/main/java/com/yfive/gbjs/domain/guide/repository/AudioGuideRepository.java (1)

40-42: 배치 조회 메서드 추가 좋습니다. 시그니처를 Set/Collection 기반으로 다듬는 것을 제안합니다.

  • 반환 타입을 Set으로 두면 DISTINCT 의미와 일치하고, 호출부에서 별도 HashSet 래핑이 불필요합니다.
  • 파라미터는 List보다 Collection이 유연합니다.

아래처럼 변경하면 호출부 단순화 + 불필요한 중복 제거 효과가 있습니다.

-  @Query("SELECT DISTINCT ag.contentId FROM AudioGuide ag WHERE ag.contentId IN :contentIds")
-  List<Long> findContentIdsWithAudioGuidesByContentIdIn(@Param("contentIds") List<Long> contentIds);
+  @Query("SELECT DISTINCT ag.contentId FROM AudioGuide ag WHERE ag.contentId IN :contentIds")
+  java.util.Set<Long> findContentIdsWithAudioGuidesByContentIdIn(
+      @Param("contentIds") java.util.Collection<Long> contentIds);

추가로, JPA 구현체에 따라 빈 컬렉션으로 IN 절을 호출하면 예외가 날 수 있으므로(예: IN ()) 호출부에서 빈 컬렉션은 바로 빈 결과를 반환하도록 가드해 주세요.

빈 컬렉션 가드가 필요한지 확인하고 싶다면 DB 벤더/버전을 공유해 주세요(Oracle의 IN 파라미터 개수 제한도 고려 필요).

src/main/java/com/yfive/gbjs/domain/spot/service/SpotServiceImpl.java (2)

432-439: 빈/중복/널 ID 가드 + 호출 단순화로 안전성과 효율 개선

  • spotId 중복·널을 미리 제거하고 빈 경우 즉시 반환하면 불필요한 DB 호출을 막습니다.
  • 저장소 메서드가 List만 받는 경우가 아니라면 Collection으로 바꾸고 호출부 래핑을 제거하는 것이 깔끔합니다(레포 시그니처 변경 제안과 연계).
-    // 1. 모든 spotId를 추출
-    List<Long> allSpotIds =
-        allSpots.stream().map(SpotResponse::getSpotId).collect(Collectors.toList());
-
-    // 2. 추출된 spotId 목록으로 오디오 가이드가 존재하는 contentId들을 한 번에 조회
-    Set<Long> contentIdsWithAudioGuides =
-        new HashSet<>(audioGuideRepository.findContentIdsWithAudioGuidesByContentIdIn(allSpotIds));
+    // 1. 모든 spotId를 추출(널 제거 + 중복 제거)
+    java.util.Set<Long> allSpotIds = allSpots.stream()
+        .map(SpotResponse::getSpotId)
+        .filter(java.util.Objects::nonNull)
+        .collect(Collectors.toSet());
+    if (allSpotIds.isEmpty()) {
+      return java.util.List.of();
+    }
+
+    // 2. 배치 조회
+    java.util.Set<Long> contentIdsWithAudioGuides =
+        new java.util.HashSet<>(audioGuideRepository
+            .findContentIdsWithAudioGuidesByContentIdIn(new java.util.ArrayList<>(allSpotIds)));

레포가 제안대로 Collection/Set 시그니처로 바뀌면 위 호출부는 아래처럼 더 단순해집니다(참고):

Set<Long> contentIdsWithAudioGuides =
    audioGuideRepository.findContentIdsWithAudioGuidesByContentIdIn(allSpotIds);
  • DB가 Oracle 등 IN 파라미터 개수 제한(예: 1000)이 있는지 확인 부탁드립니다. 제한이 있다면 allSpotIds를 청크로 나눠 쿼리 후 합치는 처리가 필요합니다. 필요 시 청크 유틸 제공 가능합니다.

445-446: 정렬 전에 필터링하여 작업량 감소

필터링을 먼저 수행하면 비교/정렬 대상이 줄어 성능이 나아집니다(최대 1000건 정렬 → 오디오가이드 존재 건만 정렬).

-    return allSpots.stream()
-        .sorted(
-            Comparator.comparing(
-                SpotResponse::getDistance, Comparator.nullsLast(Double::compareTo)))
-        .filter(
-            // 3. Set을 사용하여 메모리에서 빠르게 필터링
-            spot -> contentIdsWithAudioGuides.contains(spot.getSpotId()))
+    return allSpots.stream()
+        // 3. Set을 사용하여 메모리에서 빠르게 필터링
+        .filter(spot -> contentIdsWithAudioGuides.contains(spot.getSpotId()))
+        .sorted(
+            Comparator.comparing(
+                SpotResponse::getDistance, Comparator.nullsLast(Double::compareTo)))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9bd42e and e736de4.

📒 Files selected for processing (2)
  • src/main/java/com/yfive/gbjs/domain/guide/repository/AudioGuideRepository.java (1 hunks)
  • src/main/java/com/yfive/gbjs/domain/spot/service/SpotServiceImpl.java (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and Test
🔇 Additional comments (2)
src/main/java/com/yfive/gbjs/domain/spot/service/SpotServiceImpl.java (1)

10-13: 새 import 추가 OK

HashSet, Set, Collectors 사용과 일치합니다. 불필요한 import 없음.

src/main/java/com/yfive/gbjs/domain/guide/repository/AudioGuideRepository.java (1)

40-42: content_id 단일 컬럼 인덱스 추가 권장

src/main/java/com/yfive/gbjs/domain/guide/entity/AudioGuide.java의 AudioGuide 엔티티에 content_id에 대한 @table(indexes=...) / @Index 정의가 없고 레포에서 마이그레이션/DDL 파일도 발견되지 않았습니다. 트래픽이 많은 핫패스일 가능성이 있으니 audio_guide.content_id에 단일 컬럼 인덱스 추가(엔티티의 @table(indexes = @Index(columnList = "content_id")) 또는 DB 마이그레이션)를 적용하세요.

@joonyee joonyee merged commit c38f42b into develop Sep 17, 2025
5 checks passed
@joonyee joonyee deleted the refactor/audio_spot branch September 17, 2025 15:03
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.

♻️Refactor: 내주변 오디오 가이드 관광지 조회 속도개선

1 participant