Skip to content

Commit

Permalink
[refac] 연관검색어 리뉴얼 로직 개선
Browse files Browse the repository at this point in the history
  • Loading branch information
wjdtkdgns committed May 12, 2024
1 parent 69bd0db commit 4882f8d
Show file tree
Hide file tree
Showing 13 changed files with 246 additions and 52 deletions.

This file was deleted.

30 changes: 30 additions & 0 deletions Api/src/main/java/allchive/server/api/common/util/StringUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package allchive.server.api.common.util;


import allchive.server.core.error.exception.EmptyParamValueException;
import org.springframework.stereotype.Component;

import static allchive.server.core.consts.AllchiveConst.HANGUL_BASE;
import static allchive.server.core.consts.AllchiveConst.KOREAN_ALPHA;

@Component
public class StringUtil {
public static void checkEmptyString(String param) {
if (param.equals("")) {
throw EmptyParamValueException.EXCEPTION;
}
}

public static char extractKoreanInitial(char ch) {
int index = (ch - HANGUL_BASE) / (21 * 28); // 21개의 중성, 28개의 종성
return KOREAN_ALPHA[index];
}

public static boolean isEnglish(char ch) {
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}

public static boolean isKorean(char ch) {
return (ch >= '\uAC00' && ch <= '\uD7A3');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import static allchive.server.core.consts.AllchiveConst.ASTERISK;
import static allchive.server.core.consts.AllchiveConst.SEARCH_KEY;

import allchive.server.api.common.util.StringParamUtil;
import allchive.server.api.common.util.StringUtil;
import allchive.server.api.search.model.dto.response.SearchListResponse;
import allchive.server.core.annotation.UseCase;
import java.util.ArrayList;
Expand Down Expand Up @@ -33,7 +33,7 @@ public SearchListResponse execute(String word) {
}

private void validateExecution(String word) {
StringParamUtil.checkEmptyString(word);
StringUtil.checkEmptyString(word);
}

private List<String> getAutoCompleteList(Set<String> rangeList, String keyword) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package allchive.server.api.search.service;

import static allchive.server.core.consts.AllchiveConst.ASTERISK;
import static allchive.server.core.consts.AllchiveConst.SEARCH_KEY;
import static allchive.server.core.consts.AllchiveConst.*;

import allchive.server.api.common.util.StringUtil;
import allchive.server.core.annotation.UseCase;
import allchive.server.domain.domains.archiving.adaptor.ArchivingAdaptor;
import allchive.server.domain.domains.archiving.domain.Archiving;
import allchive.server.domain.domains.content.adaptor.TagAdaptor;
import allchive.server.domain.domains.content.domain.Tag;
import java.util.HashSet;
import java.util.Set;

import java.util.*;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -38,40 +42,156 @@ public void executeForce() {
}

private void renewalData() {
redisTemplate.delete(SEARCH_KEY);
long startTime = System.currentTimeMillis();
delete();
renewalArchiving();
renewalTag();
long stopTime = System.currentTimeMillis();
log.info("{}", stopTime - startTime);
}

private void renewalTag() {
Set<Tag> tags = new HashSet<>(tagAdaptor.findAll());
tags.forEach(
tag -> {
redisTemplate.opsForZSet().add(SEARCH_KEY, tag.getName().trim() + ASTERISK, 0);
for (int index = 0; index <= tag.getName().length(); index++) {
redisTemplate
.opsForZSet()
.add(SEARCH_KEY, tag.getName().trim().substring(0, index), 0);
private void delete() {
redisTemplate.executePipelined((RedisCallback<Object>)
redisConnection -> {
for (char c = 'A'; c <= 'Z'; c++) {
String key = SEARCH_KEY + c;
redisConnection.del(key.getBytes());
}

for (int index = 0; index < 19; index++) {
String key = SEARCH_KEY + KOREAN_ALPHA[index];
redisConnection.del(key.getBytes());
}

for (int index = 0; index < 9; index++) {
String key = SEARCH_KEY + index;
redisConnection.del(key.getBytes());
}

redisConnection.del((SEARCH_KEY + '?').getBytes());
return null;
});
}

private void renewalTag() {
int pageNum = 0;
while (true) {
PageRequest pageRequest = PageRequest.of(pageNum, BULK_SIZE);
Slice<Tag> slicedTags = tagAdaptor.querySliceTag(pageRequest);
Set<Tag> tags = new HashSet<>(slicedTags.getContent());
redisTemplate.executePipelined(
(RedisCallback<Object>)
redisConnection -> {
tags.forEach(
tag -> {
String key;
if (StringUtil.isKorean(
tag.getName().trim().charAt(0))) {
key =
SEARCH_KEY
+ StringUtil.extractKoreanInitial(
tag.getName()
.trim()
.charAt(0));
} else {
key =
SEARCH_KEY
+ tag.getName()
.trim()
.toUpperCase()
.charAt(0);
}
redisConnection
.zSetCommands()
.zAdd(
key.getBytes(),
0,
(tag.getName().trim() + ASTERISK)
.getBytes());
for (int index = 0;
index <= tag.getName().length();
index++) {
redisConnection
.zSetCommands()
.zAdd(
key.getBytes(),
0,
tag.getName()
.trim()
.substring(0, index)
.getBytes());
}
});
return null;
});

if (!slicedTags.hasNext()) {
break;
}
pageNum++;
}
}

private void renewalArchiving() {
Set<Archiving> archivings =
new HashSet<>(archivingAdaptor.findAllByPublicStatus(Boolean.TRUE));
archivings.forEach(
archiving -> {
redisTemplate
.opsForZSet()
.add(SEARCH_KEY, archiving.getTitle().trim() + ASTERISK, 0);
for (int index = 0; index <= archiving.getTitle().length(); index++) {
redisTemplate
.opsForZSet()
.add(
SEARCH_KEY,
archiving.getTitle().trim().substring(0, index),
0);
}
});
int pageNum = 0;
while (true) {
PageRequest pageRequest = PageRequest.of(pageNum, BULK_SIZE);
Slice<Archiving> slicedArchivings =
archivingAdaptor.querySliceArchivingByPublicStatus(pageRequest, true);
Set<Archiving> archivings = new HashSet<>(slicedArchivings.getContent());
redisTemplate.executePipelined(
(RedisCallback<Object>)
redisConnection -> {
archivings.forEach(
archiving -> {
String key;
if (StringUtil.isKorean(
archiving.getTitle().trim().charAt(0))) {
key =
SEARCH_KEY
+ StringUtil.extractKoreanInitial(
archiving
.getTitle()
.trim()
.charAt(0));
} else {
key =
SEARCH_KEY
+ archiving
.getTitle()
.trim()
.toUpperCase()
.charAt(0);
}
redisConnection
.zSetCommands()
.zAdd(
key.getBytes(),
0,
(archiving.getTitle().trim() + ASTERISK)
.getBytes());
for (int index = 0;
index <= archiving.getTitle().length();
index++) {
redisConnection
.zSetCommands()
.zAdd(
key.getBytes(),
0,
archiving
.getTitle()
.trim()
.substring(0, index)
.getBytes());
}
});
return null;
});

if (!slicedArchivings.hasNext()) {
break;
}
pageNum++;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import allchive.server.api.archiving.model.dto.response.ArchivingResponse;
import allchive.server.api.common.page.PageResponse;
import allchive.server.api.common.util.StringParamUtil;
import allchive.server.api.common.util.StringUtil;
import allchive.server.api.config.security.SecurityUtil;
import allchive.server.api.search.model.dto.response.SearchResponse;
import allchive.server.api.search.model.enums.ArchivingType;
Expand Down Expand Up @@ -65,7 +65,7 @@ public SearchResponse execute(Pageable pageable, ArchivingType type, String word
}

private void validateExecution(String word) {
StringParamUtil.checkEmptyString(word);
StringUtil.checkEmptyString(word);
}

private Set<Long> getTagArchivingIds(Long userId, String word) {
Expand Down
13 changes: 11 additions & 2 deletions Core/src/main/java/allchive/server/core/consts/AllchiveConst.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package allchive.server.core.consts;

import java.util.List;

public class AllchiveConst {
public static final String AUTH_HEADER = "Authorization";
public static final String BEARER = "Bearer ";
Expand Down Expand Up @@ -35,11 +37,18 @@ public class AllchiveConst {
"https://all-chive-bucket.s3.ap-northeast-2.amazonaws.com/";

public static final String[] SwaggerPatterns = {
"/swagger-resources/**", "/swagger-ui/**", "/v3/api-docs/**", "/v3/api-docs",
"/swagger-resources/**", "/swagger-ui/**", "/v3/api-docs/**", "/v3/api-docs",
};

public static final String SEARCH_KEY = "ARCHIVING_TITLE";
public static final String SEARCH_KEY = "SEARCH_KEY_";
public static final String ASTERISK = "*";
public static final int BULK_SIZE = 100;
public static final char[] KOREAN_ALPHA = {
'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ',
'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
};
// 한글 유니코드에서 '가'의 코드 포인트
public static final int HANGUL_BASE = 0xAC00;

public static final int PLUS_ONE = 1;
public static final int MINUS_ONE = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,9 @@ public List<Archiving> queryArchivingOrderByScrapCntLimit5ExceptBlockList(
List<Long> blockList) {
return archivingRepository.queryArchivingOrderByScrapCntLimit5ExceptBlockList(blockList);
}

public Slice<Archiving> querySliceArchivingByPublicStatus(
Pageable pageable, Boolean publicStatus) {
return archivingRepository.querySliceArchivingByPublicStatus(pageable, publicStatus);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ Page<Archiving> querySliceArchivingByKeywordExceptBlockOrderByTagArchvingIds(
Long userId);

List<Archiving> queryArchivingOrderByScrapCntLimit5ExceptBlockList(List<Long> blockList);

Slice<Archiving> querySliceArchivingByPublicStatus(Pageable pageable, Boolean publicStatus);
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,20 @@ public List<Archiving> queryArchivingOrderByScrapCntLimit5ExceptBlockList(
.fetch();
}

@Override
public Slice<Archiving> querySliceArchivingByPublicStatus(
Pageable pageable, Boolean publicStatus) {
List<Archiving> archivings =
queryFactory
.select(archiving)
.from(archiving)
.where(publicStatusEq(publicStatus), deleteStatusFalse())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + PLUS_ONE)
.fetch();
return SliceUtil.toSlice(archivings, pageable);
}

private BooleanExpression userIdNotIn(List<Long> blockList) {
return archiving.userId.notIn(blockList);
}
Expand All @@ -168,6 +182,10 @@ private BooleanExpression publicStatusTrue() {
return archiving.publicStatus.eq(Boolean.TRUE);
}

private BooleanExpression publicStatusEq(Boolean publicStatus) {
return archiving.publicStatus.eq(publicStatus);
}

private BooleanExpression categoryEq(Category category) {
if (category.equals(Category.ALL)) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import allchive.server.domain.domains.content.repository.TagRepository;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;

@Adaptor
@RequiredArgsConstructor
Expand Down Expand Up @@ -52,4 +54,8 @@ public List<Tag> queryTagByUserIdContainName(Long userId, String word) {
public List<Tag> findAll() {
return tagRepository.findAll();
}

public Slice<Tag> querySliceTag(Pageable pageable) {
return tagRepository.querySliceTag(pageable);
}
}
Loading

0 comments on commit 4882f8d

Please sign in to comment.