1. 문제상황
- Party, community, lecture, Project 등의 여려거아의 통합 검색 기능에서 문제가 발생
- 검색어를 입력했을 때 필터링 없이 전체 결과가 출력
- 검색 조건이 제대로 적용되지 않음
이로 인하여 검색 결과가 너무 광범위하게 반환되거나, 원하는 데이터를 찾기 어려운 상황 발생 특히, 다양한 검색 조건을 조합해도 원하는 결과를 얻지 못하는 문제가 발생.
2. 원인 분석
- 문제의 원인
- SearchService 클래스 로직
- SearchService에서 조건 중 하나인 Content 검색 로직이 다른 조건인 BoardType 조건 내부에 포함되어 있어, 동작하지 못하는 문제가 발생.
if (request.getBoardType() != null && !request.getBoardType().isEmpty()) {
// BoardType 검색
if (request.getContent() != null && !request.getContent().isEmpty()) {
// Content 검색 로직
}
}
- 엔티티별 필드 매핑
- 검색 대상 엔티티별로 접근해야 할 필드가 명확이 구분되지 않아, 잘못된 데이터 필드 접근으로 인해 검색 결과가 올바르게 반환되지 않는 문제가 발생.
- 검색 대상 엔티티별로 접근해야 할 필드가 명확이 구분되지 않아, 잘못된 데이터 필드 접근으로 인해 검색 결과가 올바르게 반환되지 않는 문제가 발생.
3. 해결 방법
- 각각의 검색 조건 독립
- 각 검색 조건이 독립적으로 동작하도록 로직을 재구성
- 특정 조건에 종속되지 않고, 모든 조건이 개별적으로 결과를 필터링하게 구현
- 명확한 엔티티별 필드 매핑
- 각 엔티티에 적합한 필드로 검색을 진행하도록 로직을 수정
@Slf4j
public class SearchSpecificationUtil {
public static <T> Specification<T> buildSpecification(IntegrationSearchRequest request) {
List<Specification<T>> specs = new ArrayList<>();
// 1. Content 검색
if (request.getContent() != null && !request.getContent().isEmpty()) {
specs.add((root, query, criteriaBuilder) -> {
String keyword = "%" + request.getContent().toLowerCase() + "%";
String entity = root.getModel().getJavaType().getSimpleName();
return switch (entity) {
case "Lecture" -> criteriaBuilder.like(criteriaBuilder.lower(root.get("description")), keyword);
case "Party" -> criteriaBuilder.like(criteriaBuilder.lower(root.get("contents")), keyword);
case "ProjectWithTutor" -> criteriaBuilder.like(criteriaBuilder.lower(root.get("description")), keyword);
case "Community" -> criteriaBuilder.like(criteriaBuilder.lower(root.get("content")), keyword);
default -> criteriaBuilder.isTrue(criteriaBuilder.literal(true)); // 조건이 없는 경우
};
});
}
// 2. BoardType 검색
if (request.getBoardType() != null && !request.getBoardType().isEmpty()) {
specs.add((root, query, criteriaBuilder) -> {
if (root.getModel().getJavaType().getSimpleName().equals("Lecture")) {
return criteriaBuilder.equal(criteriaBuilder.literal(true),
request.getBoardType().equalsIgnoreCase("lecture"));
} else {
return criteriaBuilder.equal(criteriaBuilder.lower(root.get("boardType")),
request.getBoardType().toLowerCase());
}
});
}
// 3. Title 검색
if (request.getTitle() != null && !request.getTitle().isEmpty()) {
specs.add((root, query, criteriaBuilder) ->
criteriaBuilder.like(criteriaBuilder.lower(root.get("title")),
"%" + request.getTitle().toLowerCase() + "%"));
}
// 4. 검색 조건이 없을 때
if (specs.isEmpty()) {
return (root, query, criteriaBuilder) -> criteriaBuilder.isNull(root.get("id"));
}
// 5. 모든 조건을 AND로 결합
return specs.stream().reduce(Specification::and).orElse((root, query, criteriaBuilder) -> criteriaBuilder.isNotNull(root.get("id")));
}
}
4. 결론
- 검색 조건의 독립성
- 검색 조건이 서로 영향을 주지 않고 개별적으로 동작하여, 보다 정밀한 결과를 제공할 수 있게 됨
- 검색 정확도 및 성능 향상
- 잘못된 필드 접근 문제를 해결하고, 정확한 조건으로 데이터를 필터링하여 사용자 경험이 개선되었음.
- 대소문자 구분 없는 검색으로 편의성 증가
- 구조적 개선으로 유지보수성 향상
- 검색 조건이 추가되더라도 독립적으로 적용되도록 설계하여 유지보수와 확장이 용이
'트러블슈팅' 카테고리의 다른 글
Hibernate LazyInitailizationException (0) | 2024.11.26 |
---|---|
QueryDSL 검색 조건이 null로 반환되는 문제 (0) | 2024.11.26 |
Rest Template과 JDBC Template (4) | 2024.10.20 |
최적화? Indexing? (0) | 2024.10.18 |
AOP + Proxy (0) | 2024.10.13 |