Free Lines Arrow
본문 바로가기
DataBase/Redis

[Redis] ZSetOperations

by skahn1215 2024. 10. 5.
728x90
반응형

ZSetOperations

  • ZSetOperations는 Redis에서 제공하는 sorted set(정렬된 집합)에 대한 작업을 수행하는 인터페이스이다.
  • ZSetOperations을 이용하여 레디스에서 정렬을 구현할수 있다. 

 

레디스를 선택한 이유

  • 트래픽이 많이 발생하는 상황에서 QPS를 줄이기 위해 사용한다.
  • 뉴스 데이터는 객체에대해서 CRUD 가 많이 발생하지 않는다.
  • 뉴스 데이터를 '카테고리별' 최신순으로 가져와야한다.
  • 뉴스 데이터는 30일 까지만 보관한다.

 

ZSetOperations에서 사용할 기능

Boolean add(K key, V value, double score);

 

  • key:   유니크한 값
  • value: 키에 대한 값
  • score: 키에 대한 스코어 점수

reverseRange(K key, long start, long end)
  • key: 유니크 값
  • start: index 시작값 
  • end:  index 종료값

rangeByScore(K key, double min, double max)
  • key: 유니크 값
  • min: 검색할 score 의 최소값
  • max: 검색할 score의 최대값

 

ZSetOperations 예제

1. 뉴스아이디를 카테고리별 등록시간별로 저장

ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();

// 뉴스 아이디 1, 2번은 16시에 등록
LocalDateTime localDateTime = LocalDateTime.of(2024, 10, 5, 16, 0, 0);
long regDttmMilli = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
zSetOperations.add("news:category:issue", "1", regDttmMilli);
zSetOperations.add("news:category:issue", "2", regDttmMilli);


// 뉴스 아이디 3, 4번은 17시에 등록
LocalDateTime localDateTime2 = LocalDateTime.of(2024, 10, 5, 17, 0, 0);
long regDttmMilli2 = localDateTime2.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
zSetOperations.add("news:category:issue", "3", regDttmMilli2);
zSetOperations.add("news:category:issue", "4", regDttmMilli2);

 

 

2. 카테고리 Issue 에서 최신등록된 뉴스 3개 가져오기

ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();

LocalDateTime localDateTime = LocalDateTime.of(2024, 10, 5, 16, 0, 0);
long regDttmMilli = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
zSetOperations.add("news:category:issue", "1", regDttmMilli);
zSetOperations.add("news:category:issue", "2", regDttmMilli);


LocalDateTime localDateTime2 = LocalDateTime.of(2024, 10, 5, 17, 0, 0);
long regDttmMilli2 = localDateTime2.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
zSetOperations.add("news:category:issue", "3", regDttmMilli2);
zSetOperations.add("news:category:issue", "4", regDttmMilli2);

Set<String> newsByCategory = zSetOperations.reverseRange("news:category:issue", 0, 2);
for (String newsId : newsByCategory) {
    System.out.println("newsId : ".concat(newsId));
}

 

결과

4번 3번 2번 순으로 최근 등록된 뉴스를 가져왔다.

newsId : 4
newsId : 3
newsId : 2

 

3. 카테고리 Issue 에서 등록된 시간으로 조회하기

rangeByScore를 이용하여 등록된 시간으로 조회를 한다.
min, max 에 값은 값을 넣어주면 해당 값으로 조회를 할 수 있다. 

LocalDateTime localDateTime = LocalDateTime.of(2024, 10, 5, 16, 0, 0);
long regDttmMilli = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
Set<String> newsByCategory2 = zSetOperations.rangeByScore("news:category:issue", regDttmMilli, regDttmMilli);
for (String newsId : newsByCategory2) {
    System.out.println("newsId : ".concat(newsId));
}


결과

16시에 등록한 뉴스 2개의 아이디 값을 조회 한다. 

newsId : 1
newsId : 2

 

 

 

 

전체코드

@Repository
@RequiredArgsConstructor
public class NewsRepository {
    private final RedisTemplate<String, String> redisTemplate;
    private ValueOperations<String, String> valueOperations;
    private  ZSetOperations<String, String> zSetOperations;

    private final ObjectMapper objectMapper;

    private final String NEW_BY_DATE_KEY = "news_by_date";

    @PostConstruct
    public void init() {
        valueOperations = redisTemplate.opsForValue();
        zSetOperations = redisTemplate.opsForZSet();
    }

    public void save(News news) throws JsonProcessingException {
        Integer seq = news.getSeq();
        String category = "news:category:".concat(news.getCategory());
        String redisMemberId = "news:".concat(String.valueOf(seq));

        String jsonStringData = objectMapper.writeValueAsString(news);
        long regDttm = Instant.now().toEpochMilli();
        long regDt = LocalDate.now().toEpochDay();

        valueOperations.set(redisMemberId,  jsonStringData);
        zSetOperations.add(category, redisMemberId, regDttm);
        zSetOperations.add(NEW_BY_DATE_KEY, redisMemberId, regDt);
    }


    public Set<String> findByCategory(String category, int limit) {
        String categoryKey = "news:category:".concat(category);
        // Sorted Set에서 최신 등록순으로 가져오기 (역순으로 조회)
        return zSetOperations.reverseRange(categoryKey, 0, limit - 1);
    }

    public Set<String> findByRegDt(LocalDate localDate) {
        long epochDay = localDate.toEpochDay();
        // Sorted Set에서 저장 순으로 가져오기
        return zSetOperations.rangeByScore(NEW_BY_DATE_KEY, epochDay, epochDay);
    }


    public <T> T converObject(String json, Class<T> clazz) throws JsonProcessingException {
        return (T)objectMapper.readValue(json, clazz);
    }
}
728x90
반응형

'DataBase > Redis' 카테고리의 다른 글

[Redis] Redis Spring boot 간단예제  (0) 2023.02.21
[Redis] Redis 시작하기  (0) 2023.02.21
[Redis] Redis 란?  (0) 2023.02.08

댓글