본문 바로가기
스프링 부트/A-ger

스프링 레디스 최근 검색어 관리하기

by illlilillil 2022. 2. 10.

거래 플랫폼 프로젝트를 진행하던중 검색 창에 최근 검색어 기능 추가를 했으면 좋겠다는 의견이 있었습니다.

 

2가지 방법을 생각했는데

첫번째는 search 엔티티를 만들어 관리하는 방식이었습니다.

두번째는 레디스에서 최근 검색어를 위해 리스트 자료구조를 이용해서 관리하는 방식을 생각했습니다.

 

첫 번째 방식은 인메모리 캐시 방식인 레디스에 비해 속도가 느릴거 같고 관리 측면에서도

원하는 사이즈가 꽉 찾을때 시간순으로 정렬한 후에 가장 오래된 컬럼을 삭제하고 다시 insert를 해야한다는 점이 번거로웠습니다.

 

그래서 엔티티를 아예 만들지않고 accountId로 식별할 수 있는 레디스 리스트를 만들어서 관리하는 방식을 택했습니다.

 

로직은 사용자가 검색을 하게되면 accesstoken으로 사용자를 조회하고, 키 값을 search::{accountId}로 설정해 관리가 용이하게 하였습니다. 빈 스트링을 무시하도록 했고 redisTemplate.opsForList로 레디스의 리스트 객체들을 가져옵니다.

레디스 리스트를 다루기 위한 메소드는 leftpush,leftpop,rightpush,rightpo이 있어 큐처럼 이용할 수 있습니다.

중복 키워드 제거를 위해 Set 자료구조도 고려를 해봤지만 큐처럼 자료를 넣었다 뺄 수 없어 사용하지 않았습니다.

사이즈가 최대 5개밖에 안되기 때문에 for문으로 같은 키워드가 있으면 키워드에 넣지 않도록 했습니다.

 

키를 파라미터로 하여 조회한 사이즈가 5 미만인 경우 rightpush 메서드로 리스트의 오른쪽에 데이터를 넣습니다.

사이즈가 5가 되면 가장 처음 넣은 키워드를 빼기 위해 leftPop을 하고 rightpush를 해줍니다.

 

public void postKeyword(String accessToken,String keyword) {
    log.info("keyword:{}",keyword);
    if(keyword==null) return;
    Account accountByAccessToken = accountService.findAccountByAccessToken(accessToken);
    String key = "search::"+accountByAccessToken.getAccountId();
    ListOperations listOperations = redisTemplate.opsForList();
    for(Object pastKeyword:listOperations.range(key,0,listOperations.size(key))) {
        if(String.valueOf(pastKeyword).equals(keyword)) return;
    }
    if(listOperations.size(key)<5) {
        listOperations.rightPush(key,keyword);
    }
    else if(listOperations.size(key)==5) {
        listOperations.leftPop(key);
        listOperations.rightPush(key,keyword);
    }
}

조회부분입니다. accessToken으로 조회한 뒤에 키 값을 정의해주고 range 메서드로 처음부터 리스트의 사이즈만큼 조회하고 값을 반환해줍니다.

public List<String> getSearchList(String accessToken) {
    Account accountByAccessToken = accountService.findAccountByAccessToken(accessToken);
    String key = "search::"+accountByAccessToken.getAccountId();
    ListOperations listOperations = redisTemplate.opsForList();
    return listOperations.range(key, 0, listOperations.size(key));
}

레디스 생성은 끝났고 레디스 삭제 시점에 대한 고민이 있었는데요.

일정 기간을 마다 삭제하는 의견과 계정이 삭제되는 시점에 같이 삭제하자는 의견이 있었습니다.

데이터 양이 작고 평소 이용하는 서비스를 봐도 시간이 지난다고 데이터가 삭제되는 경우는 본 적이 없어 계정 삭제 시점에 같이 삭제하기로 의견을 모았습니다.

 

댓글