diff --git a/src/main/java/org/ezcode/codetest/application/problem/dto/response/ProblemSearchResponse.java b/src/main/java/org/ezcode/codetest/application/problem/dto/response/ProblemSearchResponse.java index 6982b6e1..22ca1ef3 100644 --- a/src/main/java/org/ezcode/codetest/application/problem/dto/response/ProblemSearchResponse.java +++ b/src/main/java/org/ezcode/codetest/application/problem/dto/response/ProblemSearchResponse.java @@ -2,6 +2,7 @@ import java.util.List; +import org.ezcode.codetest.domain.problem.model.entity.Problem; import org.ezcode.codetest.domain.problem.model.entity.ProblemSearchDocument; import lombok.Builder; @@ -36,4 +37,17 @@ public static ProblemSearchResponse from(ProblemSearchDocument document) { .score(document.getScore()) .build(); } + + public static ProblemSearchResponse from(Problem problem) { + + return ProblemSearchResponse.builder() + .id(problem.getId()) + .title(problem.getTitle()) + .category(null) // TODO: 카테고리 입력해줘야 함 + .difficulty(problem.getDifficulty().getDifficulty()) + .reference(problem.getReference().toString()) + .description(problem.getDescription()) + .score(problem.getScore()) + .build(); + } } diff --git a/src/main/java/org/ezcode/codetest/application/problem/service/ProblemSearchService.java b/src/main/java/org/ezcode/codetest/application/problem/service/ProblemSearchService.java index 411a1f98..572b4c05 100644 --- a/src/main/java/org/ezcode/codetest/application/problem/service/ProblemSearchService.java +++ b/src/main/java/org/ezcode/codetest/application/problem/service/ProblemSearchService.java @@ -1,15 +1,11 @@ package org.ezcode.codetest.application.problem.service; -import java.util.Collection; import java.util.List; -import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.ezcode.codetest.application.problem.dto.response.ProblemSearchResponse; -import org.ezcode.codetest.domain.problem.model.entity.ProblemSearchDocument; import org.ezcode.codetest.domain.problem.service.ProblemSearchDomainService; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -20,48 +16,18 @@ public class ProblemSearchService { private final ProblemSearchDomainService searchDomainService; + // Redis 캐시 적용 (Cache Name: suggestions, Key: keyword) + @Cacheable(value = "suggestions", key = "#keyword", unless = "#result.isEmpty()") public Set getProblemSuggestions(String keyword) { - return searchDomainService - .getSuggestionsByKeyword(keyword) - .stream() - .flatMap(doc -> { - Stream.Builder searchedKeyword = Stream.builder(); - - Optional.ofNullable(doc.getTitle()).ifPresent(searchedKeyword::add); - Optional.ofNullable(doc.getReference()) - .map(Enum::toString) - .ifPresent(searchedKeyword::add); - Optional.ofNullable(doc.getDifficulty()) - .ifPresent(searchedKeyword::add); - Optional.ofNullable(doc.getDescription()) - .ifPresent(searchedKeyword::add); - Optional.ofNullable(doc.getDifficultyEn()) - .map(Enum::toString) - .ifPresent(searchedKeyword::add); - Optional.ofNullable(doc.getReferenceKor()) - .ifPresent(searchedKeyword::add); - - Optional.ofNullable(doc.getCategories()) - .stream() - .flatMap(Collection::stream) - .forEach(searchedKeyword::add); - - Optional.ofNullable(doc.getCategoriesKor()) - .stream() - .flatMap(Collection::stream) - .forEach(searchedKeyword::add); - - return searchedKeyword.build(); - }) - .map(String::toUpperCase) - .collect(Collectors.toSet()); + return null; } public List getProblemSearchResult(String keyword) { - List results = searchDomainService.searchByKeywordMatch(keyword); - - return results.stream().map(ProblemSearchResponse::from).toList(); + return searchDomainService.searchByKeywordMatch(keyword) + .stream() + .map(ProblemSearchResponse::from) + .toList(); } } diff --git a/src/main/java/org/ezcode/codetest/domain/problem/repository/ProblemSearchRepository.java b/src/main/java/org/ezcode/codetest/domain/problem/repository/ProblemSearchRepository.java new file mode 100644 index 00000000..ffde833b --- /dev/null +++ b/src/main/java/org/ezcode/codetest/domain/problem/repository/ProblemSearchRepository.java @@ -0,0 +1,11 @@ +package org.ezcode.codetest.domain.problem.repository; + +import java.util.List; + +import org.ezcode.codetest.domain.problem.model.entity.Problem; + +public interface ProblemSearchRepository { + + // 검색용 (검색 전용 DTO 또는 엔티티 리턴) + List searchProblems(String keyword); +} diff --git a/src/main/java/org/ezcode/codetest/domain/problem/service/ProblemSearchDomainService.java b/src/main/java/org/ezcode/codetest/domain/problem/service/ProblemSearchDomainService.java index 88561fea..68eb9f20 100644 --- a/src/main/java/org/ezcode/codetest/domain/problem/service/ProblemSearchDomainService.java +++ b/src/main/java/org/ezcode/codetest/domain/problem/service/ProblemSearchDomainService.java @@ -1,10 +1,11 @@ package org.ezcode.codetest.domain.problem.service; +import java.util.HashSet; import java.util.List; import java.util.Set; -import org.ezcode.codetest.domain.problem.model.entity.ProblemSearchDocument; -import org.ezcode.codetest.domain.problem.repository.ProblemDocumentRepository; +import org.ezcode.codetest.domain.problem.model.entity.Problem; +import org.ezcode.codetest.domain.problem.repository.ProblemSearchRepository; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -13,15 +14,11 @@ @RequiredArgsConstructor public class ProblemSearchDomainService { - private final ProblemDocumentRepository searchRepository; + // private final ProblemDocumentRepository searchRepository; + private final ProblemSearchRepository searchRepository; - public Set getSuggestionsByKeyword(String keyword) { + public List searchByKeywordMatch(String keyword) { - return searchRepository.findDocumentContainingKeyword(keyword); - } - - public List searchByKeywordMatch(String keyword) { - - return searchRepository.findProblemsByKeyword(keyword); + return searchRepository.searchProblems(keyword); } } diff --git a/src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/problem/ProblemSearchJpaRepository.java b/src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/problem/ProblemSearchJpaRepository.java new file mode 100644 index 00000000..21322578 --- /dev/null +++ b/src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/problem/ProblemSearchJpaRepository.java @@ -0,0 +1,15 @@ +package org.ezcode.codetest.infrastructure.persistence.repository.problem; + +import java.util.List; + +import org.ezcode.codetest.domain.problem.model.entity.Problem; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface ProblemSearchJpaRepository extends JpaRepository { + + // TODO: FULLTEXT 인덱스 추가 + @Query(value = "SELECT * FROM problem WHERE title LIKE CONCAT('%', :keyword, '%') OR description LIKE CONCAT('%', :keyword, '%')", nativeQuery = true) + List searchByKeyword(@Param("keyword") String keyword); +} diff --git a/src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/problem/ProblemSearchRepositoryImpl.java b/src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/problem/ProblemSearchRepositoryImpl.java new file mode 100644 index 00000000..7e15020e --- /dev/null +++ b/src/main/java/org/ezcode/codetest/infrastructure/persistence/repository/problem/ProblemSearchRepositoryImpl.java @@ -0,0 +1,21 @@ +package org.ezcode.codetest.infrastructure.persistence.repository.problem; + +import java.util.List; + +import org.ezcode.codetest.domain.problem.model.entity.Problem; +import org.ezcode.codetest.domain.problem.repository.ProblemSearchRepository; +import org.springframework.stereotype.Repository; + +import lombok.RequiredArgsConstructor; + +@Repository +@RequiredArgsConstructor +public class ProblemSearchRepositoryImpl implements ProblemSearchRepository { + + private final ProblemSearchJpaRepository searchJpaRepository; + + @Override + public List searchProblems(String keyword) { + return searchJpaRepository.searchByKeyword(keyword); + } +}