Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public Page<ProductSearchResponseDto> getProductsV1(String productName, Category
Page<ProductSearchResponseDto> productsResponse = productRepository.findProductsOrderByReviewScore(productName, category, pageable);

if (StringUtils.hasText(productName) && !productsResponse.isEmpty()) {
searchServiceV1.saveSearchLog(productName); // 로그만 저장
searchServiceV1.saveSearchLog(productName); // 로그 저장
}
return productsResponse;
}
Expand All @@ -117,7 +117,6 @@ public Page<ProductSearchResponseDto> getProductsV2(String productName, Category

if (StringUtils.hasText(productName) && !productsResponse.isEmpty()) {
searchServiceV2.saveSearchLog(productName); // 로그 저장
searchServiceV2.increaseKeywordCount(productName); // 캐시 작업
}

return productsResponse;
Expand All @@ -131,8 +130,8 @@ public Page<ProductSearchResponseDto> getProductsV3(String productName, Category
Page<ProductSearchResponseDto> productsResponse = productRepository.findProductsOrderByReviewScore(productName, category, pageable);

if(StringUtils.hasText(productName) && !productsResponse.isEmpty()){
searchServiceV3.saveSearchLog(productName);
searchServiceV3.increaseSortedKeywordRank(productName);
searchServiceV3.saveSearchLog(productName); // 로그 저장
searchServiceV3.increaseSortedKeywordRank(productName); // 캐시 추가
}
return productsResponse;
}
Expand All @@ -154,5 +153,4 @@ public Product findProductByIdOrElseThrow(Long productId) {
);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class PopularKeywordDto {
private String keyword;
private Long count;

public static PopularKeywordDto of(String keyword, Long score) {
public static PopularKeywordDto keywordOf(String keyword, Long score) {
return new PopularKeywordDto(keyword, score);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class SearchLog {
@CreatedDate
private LocalDateTime searchedAt;

public static SearchLog of(String keyword) {
public static SearchLog keywordOf(String keyword) {
SearchLog log = new SearchLog();
log.keyword = keyword;
return log;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class SearchServiceV1 {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveSearchLog(String keyword){
if(StringUtils.hasText(keyword)){
searchLogRepository.save(SearchLog.of(keyword));
searchLogRepository.save(SearchLog.keywordOf(keyword));
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ public class PopularKeywordServiceV2 implements PopularKeywordService {
private final SearchLogRepository searchLogRepository;
private static final int MIN_DAYS = 1;
private static final int MAX_DAYS = 365;

private static final String POPULAR_KEYWORDS = "popularKeywords";

//캐시O 인기 검색어 조회
@Transactional(readOnly = true)
@Cacheable(value = "popularKeywords", key = "#days")
@Cacheable(value = POPULAR_KEYWORDS, key = "#days")
public List<PopularKeywordDto> searchPopularKeywords(int days) {
if (days < MIN_DAYS || days > MAX_DAYS) {
throw new BadRequestException("조회 일 수는 1~365 사이여야 합니다.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,60 +3,23 @@
import com.example.eightyage.domain.search.entity.SearchLog;
import com.example.eightyage.domain.search.repository.SearchLogRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.Set;

@Service
@RequiredArgsConstructor
public class SearchServiceV2 {

private final SearchLogRepository searchLogRepository;
private final CacheManager cacheManager;
private static final String KEYWORD_COUNT_MAP = "keywordCountMap";
private static final String KEYWORD_KEY_SET = "keywordKeySet";


// 검색 키워드를 로그에 저장
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveSearchLog(String keyword) {
if (StringUtils.hasText(keyword)) {
searchLogRepository.save(SearchLog.of(keyword));
}
}

// 검색 시 키워드 카운트 증가
@Transactional
public void increaseKeywordCount(String keyword) {
if (!StringUtils.hasText(keyword)) return;

Cache countCache = cacheManager.getCache(KEYWORD_COUNT_MAP);

if (countCache != null) {
String countStr = countCache.get(keyword, String.class);
long count = (countStr == null) ? 1L : Long.parseLong(countStr) + 1;
countCache.put(keyword, Long.toString(count));
}

updateKeywordSet(keyword);
}

// 캐시에 키워드 추가
private void updateKeywordSet(String keyword) {
Cache keySetCache = cacheManager.getCache(KEYWORD_KEY_SET);
if (keySetCache != null) {
Set<String> keywordSet = keySetCache.get("keywords", Set.class);
if (keywordSet == null) {
keywordSet = new HashSet<>();
}
keywordSet.add(keyword);
keySetCache.put("keywords", keywordSet);
searchLogRepository.save(SearchLog.keywordOf(keyword));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public List<PopularKeywordDto> searchPopularKeywords(int limit) {
if (keywordSet == null) {
return List.of();
}
return keywordSet.stream().map(tuple -> PopularKeywordDto.of(tuple.getValue(), Objects.requireNonNull(tuple.getScore()).longValue()))
return keywordSet.stream().map(tuple -> PopularKeywordDto.keywordOf(tuple.getValue(), Objects.requireNonNull(tuple.getScore()).longValue()))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ public class SearchServiceV3 {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveSearchLog(String keyword) {
if (StringUtils.hasText(keyword)) {
searchLogRepository.save(SearchLog.of(keyword));
searchLogRepository.save(SearchLog.keywordOf(keyword));
}
}

// 검색어 점수 증가
public void increaseSortedKeywordRank(String productName) {
redisTemplate.opsForZSet().incrementScore(RANKING_KEY, productName, 1);
redisTemplate.expire(RANKING_KEY, Duration.ofMinutes(1));
redisTemplate.expire(RANKING_KEY, Duration.ofMinutes(5));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory)

// 캐시 별로 TTL 설정
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("keywordCountMap", defaultConfig.entryTtl(Duration.ZERO));
configMap.put("keywordKeySet", defaultConfig.entryTtl(Duration.ZERO));
configMap.put("popularKeywords", defaultConfig.entryTtl(Duration.ofMinutes(5)));

return RedisCacheManager.builder(redisConnectionFactory)
Expand Down
42 changes: 21 additions & 21 deletions src/main/java/com/example/eightyage/global/config/EnvConfig.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
package com.example.eightyage.global.config;

import io.github.cdimascio.dotenv.Dotenv;
import jakarta.annotation.PostConstruct;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Configuration
public class EnvConfig {
@PostConstruct
public void init() {
Dotenv dotenv = Dotenv.load();

System.setProperty("DB_URL", dotenv.get("DB_URL"));
System.setProperty("DB_USER", dotenv.get("DB_USER"));
System.setProperty("DB_PASSWORD", dotenv.get("DB_PASSWORD"));
System.setProperty("DB_URL", dotenv.get("AWS_ACCESS_KEY"));
System.setProperty("DB_USER", dotenv.get("AWS_SECRET_KEY"));
System.setProperty("DB_PASSWORD", dotenv.get("JWT_SECRET_KEY"));
}
}
//package com.example.eightyage.global.config;
//
//import io.github.cdimascio.dotenv.Dotenv;
//import jakarta.annotation.PostConstruct;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.stereotype.Component;
//
//@Configuration
//public class EnvConfig {
// @PostConstruct
// public void init() {
// Dotenv dotenv = Dotenv.load();
//
// System.setProperty("DB_URL", dotenv.get("DB_URL"));
// System.setProperty("DB_USER", dotenv.get("DB_USER"));
// System.setProperty("DB_PASSWORD", dotenv.get("DB_PASSWORD"));
// System.setProperty("DB_URL", dotenv.get("AWS_ACCESS_KEY"));
// System.setProperty("DB_USER", dotenv.get("AWS_SECRET_KEY"));
// System.setProperty("DB_PASSWORD", dotenv.get("JWT_SECRET_KEY"));
// }
//}