fix: 강의 검색 결과 학년 정렬 누락 수정(#101) - #103
Merged
Merged
Conversation
검색 정렬 기준과 검증 방식의 선택지를 남긴다. - 정렬 기준은 학년, 관련도, 학수번호 순으로 확정. 검색 결과는 학과와 이수구분이 섞여 나와 이수구분 묶음의 의미가 약하다 - 검증은 Testcontainers MySQL 통합 테스트로 확정. 검색 경로는 #40 이후 테스트가 0건이라 이 버그가 그대로 나갔다 - 구현 중 계획을 벗어난 지점은 Deviation Log에 남겼다 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013U5wVj4Y3rBs4rpx3Hp4LK
findByKeyword만 ORDER BY에 학년이 없었고, MATCH 뒤에 방향이 빠져 관련도가 낮은 순으로 나가고 있었다. 나머지 조회 5종은 학년, 이수구분, 학수번호 순으로 정렬한다. 검색도 학년을 첫 키로 두어 전학년, 1, 2, 3, 4 순서를 맞추고, 같은 학년 안에서는 관련도가 높은 순, 관련도가 같으면 학수번호 순으로 정렬한다. grade_code는 전학년이 0이라 오름차순만으로 원하는 순서가 나온다. MATCH 컬럼 목록은 ft_idx_course_search와 어긋나면 인덱스를 못 타므로 그대로 두었다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013U5wVj4Y3rBs4rpx3Hp4LK
검색 경로는 H2가 MATCH AGAINST를 실행하지 못해 테스트가 없었고, 그래서 정렬 버그가 그대로 나갔다. Testcontainers로 실제 MySQL을 띄워 검증한다. - MySqlIntegrationTest는 트랜잭션을 걸지 않는다. InnoDB FULLTEXT 인덱스는 커밋된 행만 검색해 롤백 격리 안에서는 MATCH에 잡히지 않는다 - Flyway로 운영과 같은 스키마를 만들어 ngram 인덱스까지 재현한다 - 관련도를 검증하려고 검색어와 무관한 행을 섞었다. 모든 행이 검색어를 포함하면 idf가 0이라 관련도가 전부 같아진다 - DataSourceConfig가 spring.datasource 프로퍼티로 DataSource를 직접 만들어 ServiceConnection이 끼어들지 못한다. 컨테이너 접속 정보를 같은 프로퍼티에 주입해 연결한다 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013U5wVj4Y3rBs4rpx3Hp4LK
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013U5wVj4Y3rBs4rpx3Hp4LK
Test Results290 tests 290 ✅ 4s ⏱️ Results for commit c4b6e69. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Summary
강의 검색 결과가 다른 조회 5종과 같은 학년 정렬을 따르도록 고치고, 방향이 빠져 관련도 낮은 순으로 나가던 정렬을 높은 순으로 정정했습니다. 검색 경로에 정렬 회귀를 잡는 MySQL 통합 테스트를 함께 두었습니다.
Problem
문제 1 - 검색 결과만 학년 정렬을 타지 않음
전공, 교양, 타학과, 연계전공, HUSS 조회는 모두 학년, 이수구분, 학수번호 순으로 정렬합니다. 검색만 정렬 키에 학년이 없어, 같은 화면 흐름에서 검색으로 넘어가는 순간 강의가 학년과 무관한 순서로 나왔습니다. 학년은 학생이 수강 가능 여부를 가장 먼저 거르는 기준이라, 정렬이 빠지면 목록을 처음부터 훑어야 합니다.
문제 2 - 관련도가 낮은 순으로 나감
ORDER BY MATCH ... AGAINST뒤에 정렬 방향이 없어 기본값인 오름차순으로 동작했습니다. 검색어와 가장 동떨어진 강의가 앞에 오고, 정확히 일치하는 강의가 맨 뒤로 밀렸습니다. 정책 문서에 적힌 "관련도가 높은 순"과 정반대로 나가고 있었습니다.문제 3 - 검색 경로에 테스트가 없음
FULLTEXT 검색을 도입한 #40 이후 검색 테스트는 통째로 주석 처리돼 있었습니다. 테스트 DB인 H2가
MATCH ... AGAINST를 실행하지 못하기 때문입니다. 검증이 0건인 구간이라 위 두 결함이 걸러지지 않고 그대로 나갔습니다.Solution
해결 1 - 학년을 첫 정렬 키로
정렬의 첫 키를 학년으로 두어 다른 조회와 기준을 맞췄습니다. 전학년이 코드 0이라 오름차순만으로 전학년, 1, 2, 3, 4 순서가 나와 별도 CASE 식이 필요 없었습니다. 두 번째 키는 이수구분이 아니라 관련도로 정했는데, 검색 결과는 학과와 이수구분이 섞여 나와 이수구분 묶음이 주는 의미가 약한 반면 사용자가 직접 입력한 검색어와의 관련도가 두 번째 기준으로 더 쓸모 있기 때문입니다.
해결 2 - 관련도에 내림차순 명시
관련도 식에
DESC를 붙여 높은 순으로 정정했습니다. WHERE와 ORDER BY에 같은MATCH식이 오지만 옵티마이저가 한 번만 계산합니다.MATCH의 컬럼 목록은 FULLTEXT 인덱스 정의와 어긋나는 순간 인덱스를 타지 못하므로 손대지 않았습니다.해결 3 - Testcontainers MySQL 통합 테스트 도입
H2로는 검증할 수 없는 구간이라 실제 MySQL 컨테이너를 띄우는 통합 테스트 어노테이션을 만들었습니다. Flyway로 운영과 같은 스키마를 세워 ngram FULLTEXT 인덱스까지 재현하고, 학년, 관련도, 학수번호 세 키를 각각 검증합니다. Docker가 없는 환경에서는 이 테스트만 건너뜁니다.
두 가지 함정이 있었습니다. 이 테스트는 트랜잭션을 걸지 않는데, InnoDB FULLTEXT 인덱스는 커밋된 행만 검색해 롤백 격리 안에서 저장한 행은
MATCH에 잡히지 않기 때문입니다. 또 관련도를 검증하려면 검색어와 무관한 행을 반드시 섞어야 합니다. 모든 행이 검색어를 포함하면 idf가 0이 되어 관련도가 전부 같아집니다.해결 3-1 - 컨테이너 접속 정보 주입 방식
@ServiceConnection으로는 컨테이너가 연결되지 않았습니다. 이 프로젝트는DataSourceConfig에서spring.datasource프로퍼티로 DataSource를 직접 만들기 때문에, 부트가 연결 정보를 갈아끼우는 자동설정 경로를 타지 않습니다. 컨테이너는 떠 있는데 JPA는 H2를 붙잡고 있는 상태였습니다. 운영 코드를 건드리지 않으려고 컨테이너 접속 정보를DataSourceConfig가 읽는 바로 그 프로퍼티에 주입하는 방식으로 연결했습니다.검증
전체 테스트 290건이 통과합니다. 정렬 방향 회귀를 실제로 잡는지 확인하려고
DESC를 잠시 빼고 돌렸을 때, 의도한 관련도 검증 테스트 하나만 실패하는 것까지 보고 복원했습니다.범위 밖 변경
이슈 라벨 표기에서 이모지를 제거한 문서 커밋이 하나 함께 올라가 있습니다. #101과는 무관한 정리입니다.
Related Issue