-
Notifications
You must be signed in to change notification settings - Fork 1
refactor: 많이 조회한 게시글 키워드 구조 변경 #1061
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
seongjae6751
merged 18 commits into
develop
from
refactor/1038-popular-article-search-keyword
Mar 25, 2025
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
c7fa16d
refactor: 이벤트 작성
seongjae6751 dc6a453
refactor: 이벤트 리스너 구조로 변경
seongjae6751 8cc9608
chore: 충돌 해결
seongjae6751 46bd313
chore: 코드 원상 복구
seongjae6751 ecea772
refactor: 많이 조회한 검색어 로직 리팩토링
seongjae6751 6e29cf2
refactor: 로직 변경
seongjae6751 dc7f1a5
chore: 충돌 해결
seongjae6751 d412c9b
fix: 직렬화 해결
seongjae6751 288ba7a
refactor: 직관적인 이름으로 변경
seongjae6751 c8f63d1
refactor: 구조 단순화
seongjae6751 553e20e
fix: 동기화 에러 수정
seongjae6751 bae19b6
chore: 충돌 해결
seongjae6751 50db14b
Merge branch 'develop' of https://github.com/BCSDLab/KOIN_API_V2 into…
seongjae6751 e23f410
fix: 동기화 문제 해결
seongjae6751 1bc771c
fix: totalSearchCount 숫자 이상하게 올라가던 문제 해결
seongjae6751 4683f74
chore: 스케쥴러 동기화 시간 변경
seongjae6751 f496631
chore: 피드백 반영
seongjae6751 8b3f689
chore: 충돌 해결
seongjae6751 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
46 changes: 46 additions & 0 deletions
46
src/main/java/in/koreatech/koin/domain/community/article/model/KeywordRankingManager.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package in.koreatech.koin.domain.community.article.model; | ||
|
||
import in.koreatech.koin.domain.community.article.model.redis.PopularKeywordTracker; | ||
import in.koreatech.koin.domain.community.article.repository.ArticleSearchKeywordRepository; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
import org.springframework.data.domain.PageRequest; | ||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class KeywordRankingManager { | ||
|
||
private final PopularKeywordTracker popularKeywordTracker; | ||
private final ArticleSearchKeywordRepository keywordRepository; | ||
|
||
public List<String> getTopKeywords(int count) { | ||
List<String> primaryKeywords = new ArrayList<>(popularKeywordTracker.getTopKeywords(count)); | ||
|
||
if (primaryKeywords.size() < count) { | ||
int remainingCount = count - primaryKeywords.size(); | ||
List<String> secondaryKeywords = getBackupKeywords(remainingCount); | ||
secondaryKeywords.stream() | ||
.filter(keyword -> !primaryKeywords.contains(keyword)) | ||
.forEach(primaryKeywords::add); | ||
} | ||
|
||
return primaryKeywords; | ||
} | ||
|
||
private List<String> getBackupKeywords(int count) { | ||
LocalDateTime fromDate = LocalDateTime.now().minusWeeks(1); | ||
Pageable pageable = PageRequest.of(0, count); | ||
|
||
List<String> topKeywords = keywordRepository.findTopKeywords(fromDate, pageable); | ||
if (topKeywords.isEmpty()) { | ||
topKeywords = keywordRepository.findTopKeywordsByLatest(pageable); | ||
} | ||
return topKeywords; | ||
} | ||
Comment on lines
+15
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클래스 갯수가 늘어나더라도 크기를 작게 분리하는 것이 유지보수에 많은 도움이 된다고 생각합니다. 👍 |
||
} |
62 changes: 62 additions & 0 deletions
62
...in/java/in/koreatech/koin/domain/community/article/model/redis/PopularKeywordTracker.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package in.koreatech.koin.domain.community.article.model.redis; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.redis.core.RedisTemplate; | ||
import org.springframework.stereotype.Component; | ||
|
||
import org.springframework.data.redis.core.ZSetOperations.TypedTuple; | ||
|
||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class PopularKeywordTracker { | ||
|
||
private static final double FIXED_WEIGHT_AFTER_FIVE_SEARCHES = 0.0625; | ||
private static final int MAX_SEARCH_COUNT_FOR_WEIGHT = 10; | ||
|
||
private static final String KEYWORD_SET = "popular_keywords"; | ||
private static final String IP_SEARCH_COUNT_PREFIX = "search:count:ip:"; | ||
|
||
private final RedisTemplate<String, Object> redisTemplate; | ||
|
||
public void updateKeywordWeight(String ipAddress, String keyword) { | ||
if (keyword == null || keyword.isBlank() || ipAddress == null || ipAddress.isBlank()) { | ||
return; | ||
} | ||
|
||
String ipSearchCountKey = IP_SEARCH_COUNT_PREFIX + ipAddress; | ||
|
||
Long currentIpCount = redisTemplate.opsForHash().increment(ipSearchCountKey, keyword, 1); | ||
|
||
double additionalWeight = calculateWeight(currentIpCount); | ||
|
||
if (additionalWeight > 0) { | ||
redisTemplate.opsForZSet().incrementScore(KEYWORD_SET, keyword, additionalWeight); | ||
} | ||
} | ||
|
||
private double calculateWeight(Long currentCount) { | ||
if (currentCount <= 5) { | ||
return 1.0 / Math.pow(2, currentCount - 1); | ||
} else if (currentCount <= MAX_SEARCH_COUNT_FOR_WEIGHT) { | ||
return FIXED_WEIGHT_AFTER_FIVE_SEARCHES; | ||
} | ||
return 0.0; | ||
} | ||
|
||
public Set<String> getTopKeywords(int limit) { | ||
Set<TypedTuple<Object>> keywordTuples = redisTemplate.opsForZSet() | ||
.reverseRangeWithScores(KEYWORD_SET, 0, limit - 1); | ||
|
||
if (keywordTuples == null || keywordTuples.isEmpty()) { | ||
return Set.of(); | ||
} | ||
|
||
return keywordTuples.stream() | ||
.map(TypedTuple::getValue) | ||
.map(String::valueOf) | ||
.collect(Collectors.toSet()); | ||
} | ||
} |
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
일주일동안 검색된 keyword의 개수가 추가로 필요한 count개수에 못미치더라도 해당 갯수만큼만 반환하게 되는데
의도한 부분인가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
의도한 부분 맞습니다! 항상 클라이언트에서 요구하는 것만큼의 키워드를 반환하기 위함이였습니다