티스토리 뷰
https://github.com/okihouse/spring-boot-redis-auto-complete
위 링크의 자료를 이용
AutocompleteConfig
@Configuration
public class AutocompleteConfig {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Bean(name = {"autocompleteKeyRepository", "keyRepository"})
public AutocompleteKeyRepository keyRepository() {
// auto-complete custom key implements for test
AutocompleteKeyRepository keyRepository = new AutocompleteKeyServiceImpl(stringRedisTemplate);
return keyRepository;
}
@Bean(name = {"autocompleteRepository"})
public AutocompleteRepository autocompleteRepository(AutocompleteKeyRepository autocompleteKeyRepository) {
AutocompleteRepository autocompleteRepository = new AutocompleteServiceImpl(stringRedisTemplate, autocompleteKeyRepository);
return autocompleteRepository;
}
}
AutocompleteKeyRepository
@Repository
public interface AutocompleteKeyRepository {
String create(String word, String identifier);
double incr(String word, String identifier);
String getKey(String firstLetter);
}
AutocompleteData (VO)
public class AutocompleteData implements Comparable<AutocompleteData> {
private String value;
private int score;
public AutocompleteData(String value, int score) {
this.value = value;
this.score = score;
}
@Override
public int compareTo(AutocompleteData autocompleteData) {
return ((Integer)autocompleteData.getScore()).compareTo(this.score);
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
AutocompleteRepository
@Repository
public interface AutocompleteRepository {
String DEFAULT_DELIMITER = "§";
List<AutocompleteData> complete(final String word);
List<AutocompleteData> complete(final String word, final double min, final double max, final int offset);
void add(final String word);
double incr(final String word);
void clear(final String key);
}
AutocompleteKeyServiceImpl
@Service
public class AutocompleteKeyServiceImpl implements AutocompleteKeyRepository {
protected static final String DELIMITER = ":";
protected static final String PREFIX = "autocomplete" + DELIMITER;
private StringRedisTemplate stringRedisTemplate;
public AutocompleteKeyServiceImpl(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public String create(final String word, final String identifier) {
Assert.hasLength(word, "Word cannot be empty or null");
String trimedWord = word.trim();
String firstLetter = getPrefix(trimedWord);
String generatedKey = generateKey(firstLetter, trimedWord.length());
System.out.println("generatedKey : " + generatedKey);
if(!hasKey(generatedKey, trimedWord, identifier)) {
stringRedisTemplate.opsForZSet().add(generatedKey, trimedWord + identifier, 1);
stringRedisTemplate.opsForZSet().add(generatedKey, firstLetter, 0);
for (int index = 1; index < trimedWord.length() + 1; index++) {
stringRedisTemplate.opsForZSet().add(generatedKey, trimedWord.substring(0, index), 0);
}
}
return generatedKey;
}
@Override
public String getKey(String word) {
String firstLetter = getPrefix(word);
return generateKeyWithoutLength(firstLetter);
}
@Override
public double incr(final String word, final String identifier) {
Assert.hasLength(word, "Word cannot be empty or null");
String trimedWord = word.trim();
String firstLetter = getPrefix(trimedWord);
String generatedKey = generateKey(firstLetter, trimedWord.length());
System.out.println("generatedKey : " + generatedKey);
if(!hasKey(generatedKey, trimedWord, identifier)) return 0;
return stringRedisTemplate.opsForZSet().incrementScore(generatedKey, trimedWord + identifier, 1);
}
private String generateKey(final String firstLetter, int length){
return generateKeyWithoutLength(firstLetter) + length;
}
private String generateKeyWithoutLength(final String firstLetter){
return PREFIX + firstLetter + DELIMITER;
}
private boolean hasKey(final String key, final String word, final String identifier){
Double exist = stringRedisTemplate.opsForZSet().score(key, word.trim() + identifier);
return exist != null;
}
private String getPrefix(final String word){
return word.substring(0, 1);
}
}
AutocompleteServiceImpl
@Service
public class AutocompleteServiceImpl implements AutocompleteRepository {
private final double min = 0;
private final double max = 5;
private final int offset = 30;
private StringRedisTemplate stringRedisTemplate;
private AutocompleteKeyRepository keyRepository;
public AutocompleteServiceImpl(StringRedisTemplate stringRedisTemplate, AutocompleteKeyRepository keyRepository) {
this.stringRedisTemplate = stringRedisTemplate;
this.keyRepository = keyRepository;
}
@Override
public List<AutocompleteData> complete(@RequestParam String word) {
return complete(word, min, max, offset);
}
@Override
public List<AutocompleteData> complete(String word, double min, double max, int offset) {
Assert.hasLength(word, "Word cannot be empty or null");
String trimedWord = word.trim();
int trimedWordLength = trimedWord.length();
String key = keyRepository.getKey(trimedWord);
add(trimedWord);
incr(trimedWord);
List<AutocompleteData> autocompletes = new ArrayList<>();
for (int i = trimedWordLength; i < offset; i++) {
if (autocompletes.size() == offset) break;
Set<TypedTuple<String>> rangeResultsWithScore = stringRedisTemplate
.opsForZSet()
.reverseRangeByScoreWithScores(key + i, min, max, 0, offset);
if (rangeResultsWithScore.isEmpty()) continue;
for (TypedTuple<String> typedTuple : rangeResultsWithScore) {
if (autocompletes.size() == offset) break;
String value = typedTuple.getValue();
int minLength = Math.min(value.length(), trimedWordLength);
if (!value.endsWith(DEFAULT_DELIMITER) || !value.startsWith(trimedWord.substring(0, minLength))) continue;
autocompletes.add(new AutocompleteData(value.replace(DEFAULT_DELIMITER, ""), typedTuple.getScore().intValue()));
}
}
Collections.sort(autocompletes);
return autocompletes;
}
@Override
public void add(String word) {
keyRepository.create(word, DEFAULT_DELIMITER);
}
@Override
public double incr(String word) {
return keyRepository.incr(word, DEFAULT_DELIMITER);
}
@Override
public void clear(String key) {
stringRedisTemplate.delete(key);
}
}
Controller
@Autowired
AutocompleteKeyRepository autocompleteKeyRepository;
@Autowired
AutocompleteRepository autocompleteRepository;
@ResponseBody
@RequestMapping("/redisComplete")
public JSONResult redisSearch(@RequestParam String word) {
return JSONResult.success(autocompleteRepository.complete(word));
}
위 내용들을 각 service, repository, controller에 넣고 확인
'DataBase > Redis' 카테고리의 다른 글
[Redis] Redis-cli 한글 깨질때 방법 (0) | 2019.05.29 |
---|---|
[Redis] Redis 명령어 (0) | 2019.05.28 |
[Redis] Jedis 설치 및 사용법 (0) | 2019.05.28 |
[Redis] Spring & Redis 연동 (0) | 2019.05.28 |
[Redis] Redis-Server 시작 (0) | 2019.05.28 |