Redis 자료 구조 - ZSet (Sorted Set)

    개요

    이름에서 유추할 수 있듯이, Redis(레디스)에서 제공하는 자료 구조 중, Set과 비슷하면서도 차이점이 있는 자료 구조다. 값 자체의 중복을 허용하지 않지만, 정렬을 해주는 자료 구조이다. 정렬의 기준을 score라고 한다.

     

    명령어

    Redis - Hash에서의 예와 같이, 사용자들의 데이터를 Redis 상에서 정렬하거나 업데이트 하는 예제로 접근해 보자. 앞서 다뤘던 것과 비슷하게 해볼텐데, 이번에는 사용자의 점수(포인트)로 순위를 관리하는 예로 접근해 보고자 한다.

    user[0].point = 100
    user[1].point = 200
    user[2].point = 50

    등과 같이 사용자별로 포인트가 관리되는 상황을 가정해볼 수 있을 것이다. User들의 point를 모아서 순위를 매긴다면 프로그램에서 하는 방식과 Redis 내부에서는 다음과 같이 관리할 것이다.

    • key = users:point
    • score = point
    • member = point의 소유자

    위와 같은 예를 바탕으로, Redis가 지원하는 Sorted Set 연산 기능을 살펴보자.

     

    ZADD

    127.0.0.1:6379> help zadd
    
      ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]
      summary: Add one or more members to a sorted set, or update its score if it already exists
      since: 1.2.0
      group: sorted_set

    기본 명령어는 키, 스코어, 멤버의 순으로 입력한다.

    // 한 개의 데이터를 추가
    127.0.0.1:6379> zadd users:point 0 jason
    (integer) 1
    
    // 여러 개의 데이터를 추가
    127.0.0.1:6379> zadd users:point 10 mason 20 jane
    (integer) 2

    위의 예에서 보는 바와 같이, 한 개 또는 여러 개의 데이터를 한 번에 업데이트 할 수 있다. 키의 중복 업데이트 동작 방식애 대해 다음의 예로 확인해 본다.

    127.0.0.1:6379> zadd test 0 me
    (integer) 1
    127.0.0.1:6379> zrange test 0 -1
    1) "me"
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "0"
    127.0.0.1:6379> zadd test 100 me
    (integer) 0
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "100"
    127.0.0.1:6379> zadd test 50 me
    (integer) 0
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "50"

    위의 예에서 살펴 보다시피, set의 특성상 중복은 걸러진다고 알고 있을 것이다. 원래대로라면, 멤버는 중복인 경우는 덮어쓰지 않고, 스코어만 업데이트 한다고 하는 것이 맞을 수도 있는데, 기억의 편의성상 그냥 업데이트 한다고 기억하는 것이 더 좋을 것 같다. 물론, 이 경우도 NX/XX 옵션을 써서 동작을 미세하게 제어할 수 있다.

    // 기본 옵션을 사용하여 무조건 덮어 쓰는 경우
    127.0.0.1:6379> zadd test 100 me
    (integer) 0
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "100"
    127.0.0.1:6379> zadd test 50 me
    (integer) 0
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "50"
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "50"
    
    // nx 옵션을 주는 경우: 데이터가 존재하지 않을 때만 add해라
    // 사실 존재하는 경우였음
    127.0.0.1:6379> zadd test nx 30 me
    (integer) 0
    
    // 기존에 50이라고 존재했는데, 30으로 업데이트하라고 했고,
    // 이미 데이터가 존재했으므로 요청을 무시하고 50으로 유지됨
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "50"
    
    // xx 옵션을 주는 경우: 데이터가 존재하는 경우에만 add (update) 해라
    // 이미 50으로 존재함
    127.0.0.1:6379> zadd test xx 30 me
    (integer) 0
    
    // 50 -> 30으로 업데이트
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "30"
    
    // 만약, me 데이터가 없다면 추가가 안될 것이다
    127.0.0.1:6379> zadd test2 xx 30 me
    (integer) 0
    127.0.0.1:6379> zrange test2 0 -1 withscores
    (empty array)

    GT/LT 옵션은 기존에 값이 존재하지 않으면 그냥 추가를 하지만, 만약 기존 값이 존재한다면 값을 비교하여 연산을 한다.

    • GT: 지금 추가하려는 멤버의 스코어가 더 크면 추가 (없으면 그냥 추가)
    • LT: 지금 추가하려는 멤버의 스코어가 더 작으면 추가 (없으면 그냥 추가)
    // 기존 값
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "30"
    
    // gt 20으로 추가 시도
    127.0.0.1:6379> zadd test gt 20 me
    (integer) 0
    
    // 변화 없음
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "30"
    
    // gt 50으로 추가 시도
    127.0.0.1:6379> zadd test gt 50 me
    (integer) 0
    
    // 스코어가 업데이트 됨
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "50"
    
    // 없는 멤버일 경우
    127.0.0.1:6379> zadd test gt 10 you
    (integer) 1
    
    // 그냥 추가됨
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "you"
    2) "10"
    3) "me"
    4) "50"

    incr 옵션을 살펴보자. incr는 스코어를 증가시킨다. 양수 혹은 음수를 인자로 받아들인다.

    // 변경 전
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "you"
    2) "20"
    3) "me"
    4) "50"
    
    // 스코어를 20만큼 증가시킨다.
    127.0.0.1:6379> zadd test incr 20 you
    "40"
    
    // 스코어를 10만큼 증가시킨다.
    127.0.0.1:6379> zadd test incr 10 you
    "50"
    
    // 최종 스코어는 50이 되었다.
    127.0.0.1:6379> zrange test 0 -1 withscores
    1) "me"
    2) "50"
    3) "you"
    4) "50"

     

    ZRANGE, ZREVRANGE

    127.0.0.1:6379> help zrange
    
      ZRANGE key min max [BYSCORE|BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
      summary: Return a range of members in a sorted set
      since: 1.2.0
      group: sorted_set
    
    127.0.0.1:6379> help zrevrange
    
      ZREVRANGE key start stop [WITHSCORES]
      summary: Return a range of members in a sorted set, by index, with scores ordered from high to low
      since: 1.2.0
      group: sorted_set

    위의 예에서 이미 인용되었듯이, ZRANGE와 ZREVRANGE는 정렬된 데이터의 순서대로 조회하는 명령어이다. ZRANGE는 스코어가 낮은 순서부터 높은 순서로 정렬한다. ZREVRANGE는 역순으로, 스코어가 높은 순서에서 낮은 순서로 정렬한다.

    // 스코어가 낮은 것부터 높은 순으로 5개 조회하기
    127.0.0.1:6379> zrange users:point 0 4
    1) "jason"
    2) "leo"
    3) "lion"
    4) "nova"
    5) "mini"
    
    // 스코어가 높은 것부터 낮은 순으로 5개 조회하기
    127.0.0.1:6379> zrevrange users:point 0 4
    1) "max"
    2) "mike"
    3) "steve"
    4) "ted"
    5) "noah"

    정렬된 근거를 보려면, withscores 옵션을 각각 뒤에 붙여보면 보다 명확한 근거를 볼 수 있다.

    // 위와 동일한 데이터를 스코어와 함께 조회한다. 다만, jason -> 0, leo -> 2 등과 같이 멤버값과 스코어를 번갈아 출력한다.
    127.0.0.1:6379> zrange users:point 0 4 withscores
     1) "jason"
     2) "0"
     3) "leo"
     4) "2"
     5) "lion"
     6) "3"
     7) "nova"
     8) "3"
     9) "mini"
    10) "5"
    
    // 마찬가지로 조회한 멤버값과 스코얼르 교차로 출력한다.
    127.0.0.1:6379> zrevrange users:point 0 4 withscores
     1) "max"
     2) "500"
     3) "mike"
     4) "110"
     5) "steve"
     6) "90"
     7) "ted"
     8) "65"
     9) "noah"
    10) "60"

    만약, start를 0으로, stop을 -1로 주면 전체 조회를 한다. ZREVRANGE가 ZRANGE의 역정렬 버전이라고 보기에는 기능 차이가 크다. ZRANGE는 여러 키워드가 옵션으로 있는 반면, ZREVRANGE는 단순 조회와 WITHSCORES 옵션만 지정 가능하다. ZRANGE 명령어에 REV 옵션을 부여하면, ZREVRANGE와 동일한 기능을 수행할 수도 있다.

    127.0.0.1:6379> zrange users:point 0 4
    1) "jason"
    2) "leo"
    3) "lion"
    4) "nova"
    5) "mini"
    
    // 역순 조회
    127.0.0.1:6379> zrange users:point 0 4 rev
    1) "max"
    2) "mike"
    3) "steve"
    4) "ted"
    5) "noah"

    ZRANGE 명령어의 경우, BYSCORE 옵션과 LIMIT 옵션을 함께 사용하여 pagination과 같은 부분 조회가 가능하다. (ZREVRANGE의 경우 해당 옵션 없음)

    127.0.0.1:6379> zrange users:point 0 1000 byscore limit 0 3
    1) "jason"
    2) "leo"
    3) "lion"

     

    ZRANGEBYSCORE, ZREVRANGEBYSCORE

    127.0.0.1:6379> help zrangebyscore
    
      ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
      summary: Return a range of members in a sorted set, by score
      since: 1.0.5
      group: sorted_set
    
    127.0.0.1:6379> help zrevrangebyscore
    
      ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
      summary: Return a range of members in a sorted set, by score, with scores ordered from high to low
      since: 2.2.0
      group: sorted_set

    ZRANGEBYSCORE는 ZRANGE 명령어에 BYSCORE 옵션을 붙은 것과 같은 효과를 내는 명령어이다. ZREVRANGEBYSCORE의 경우, ZRANGEBYSCORE의 역방향 명령어인데, 사용할 수 있는 옵션이 동일하여 같은 표현력을 갖는다. 즉, ZRANGE와 그 옵션으로 ZRANGEBYSCORE를 대체할 수 있지만, ZREVRANGEBYSCORE는 대체 불가능한 셈이다. (ZREVRANGE로 대체 기능을 수행할 수 없음)

    // start = 0, stop = 1000중에, offset = 0, count = 100으로 스코어가 작은 순서부터 정렬하여 추출
    127.0.0.1:6379> zrangebyscore users:point 0 1000 limit 0 100
     1) "jason"
     2) "leo"
     3) "lion"
     4) "nova"
     5) "mini"
     6) "joey"
     7) "lex"
     8) "mason"
     9) "jane"
    10) "noah"
    11) "ted"
    12) "steve"
    13) "mike"
    14) "max"
    
    // start = 1000, stop = 0중에, offset = 0, count = 100으로 스코어가 큰 순서부터 정렬하여 추출
    127.0.0.1:6379> zrevrangebyscore users:point 1000 0 limit 0 100
     1) "max"
     2) "mike"
     3) "steve"
     4) "ted"
     5) "noah"
     6) "jane"
     7) "mason"
     8) "lex"
     9) "joey"
    10) "mini"
    11) "nova"
    12) "lion"
    13) "leo"
    14) "jason"

    ZRANGEBYSCORE와 ZREVRANGEBYSCORE는 조회 방향이 반대이기 때문에, 서로 바꿔서 사용하려면 start, stop의 값을 서로 뒤집어서 사용해 줘야 한다.

     

    ZRANK, ZREVRANK

    127.0.0.1:6379> help zrank
    
      ZRANK key member
      summary: Determine the index of a member in a sorted set
      since: 2.0.0
      group: sorted_set
    
    127.0.0.1:6379> help zrevrank
    
      ZREVRANK key member
      summary: Determine the index of a member in a sorted set, with scores ordered from high to low
      since: 2.0.0
      group: sorted_set

    순위를 조회하는 명령어이다.

    // 낮은 스코어 기준으로 정렬했을 때 몇 번째인가?
    127.0.0.1:6379> zrank users:point jane
    (integer) 8
    
    // 높은 스코어 기준으로 정렬했을 때 몇 번째인가?
    127.0.0.1:6379> zrevrank users:point jane
    (integer) 5

     

    ZSCORE

    127.0.0.1:6379> help zscore
    
      ZSCORE key member
      summary: Get the score associated with the given member in a sorted set
      since: 1.2.0
      group: sorted_set

    ZRANGE나 ZREVRANGE 명령어에서 WITHSCORES 옵션을 부여하여 모든 멤버들의 스코어를 함께 조회했었는데, 이 명령어는 지정한 멤버 딱 하나의 스코어를 확인해 준다.

    127.0.0.1:6379> zscore users:point jane
    "20"

     

    ZCARD

    127.0.0.1:6379> help zcard
    
      ZCARD key
      summary: Get the number of members in a sorted set
      since: 1.2.0
      group: sorted_set

    해당 키에 몇 개의 멤버가 등록이 되어 있는지 확인한다.

    127.0.0.1:6379> zcard users:point
    (integer) 14

     

    ZCOUNT

    127.0.0.1:6379> help zcount
    
      ZCOUNT key min max
      summary: Count the members in a sorted set with scores within the given values
      since: 2.0.0
      group: sorted_set

    ZCARD와 비슷하지만, 차이점은 스코어의 범위를 지정하는 점이다.

    // 0부터 500사이의 갯수
    127.0.0.1:6379> zcount users:point 0 500
    (integer) 14
    
    // 0부터 100사이의 갯수
    127.0.0.1:6379> zcount users:point 0 100
    (integer) 12

     

    ZSCAN

    127.0.0.1:6379> help zscan
    
      ZSCAN key cursor [MATCH pattern] [COUNT count]
      summary: Incrementally iterate sorted sets elements and associated scores
      since: 2.8.0
      group: sorted_set

    갯수를 지정하여 부분적으로 조회할 수 있는 명령어이다.

    127.0.0.1:6379> zscan users:point 0 count 5
    1) "0"
    2)  1) "jason"
        2) "0"
        3) "leo"
        4) "2"
        5) "lion"
        6) "3"
        7) "nova"
        8) "3"
        9) "mini"
       10) "5"
       11) "joey"
       12) "7"
       13) "lex"
       14) "9"
       15) "mason"
       16) "10"
       17) "jane"
       18) "20"
       19) "noah"
       20) "60"
       21) "ted"
       22) "65"
       23) "steve"
       24) "90"
       25) "mike"
       26) "110"
       27) "max"
       28) "500"

    count가 작게 지정되었지만, 성능을 감안하여 할 수 있는 만큼의 데이터를 수집해 온다.

     

    ZPOPMIN, ZPOPMAX

    127.0.0.1:6379> help zpopmin
    
      ZPOPMIN key [count]
      summary: Remove and return members with the lowest scores in a sorted set
      since: 5.0.0
      group: sorted_set
    
    127.0.0.1:6379> help zpopmax
    
      ZPOPMAX key [count]
      summary: Remove and return members with the highest scores in a sorted set
      since: 5.0.0
      group: sorted_set

    명령어 이름과 같이 POP을 하되, 최소값 혹은 최대값을 POP 한다. 그리고, 갯수도 함께 지정할 수 있다.

    // 명령어 실행 전
    127.0.0.1:6379> zrange users:point 0 -1 withscores
     1) "jason"
     2) "0"
     3) "leo"
     4) "2"
     5) "lion"
     6) "3"
     7) "nova"
     8) "3"
     9) "mini"
    10) "5"
    11) "joey"
    12) "7"
    13) "lex"
    14) "9"
    15) "mason"
    16) "10"
    17) "daniel"
    18) "20"
    19) "david"
    20) "20"
    21) "jane"
    22) "40"
    23) "noah"
    24) "60"
    25) "ted"
    26) "65"
    27) "steve"
    28) "90"
    29) "mike"
    30) "110"
    31) "max"
    32) "500"
    
    // 최소값을 1개 pop 한다.
    127.0.0.1:6379> zpopmin users:point 1
    1) "jason"
    2) "0"
    
    // 결과 확인
    127.0.0.1:6379> zrange users:point 0 -1 withscores
     1) "leo"
     2) "2"
     3) "lion"
     4) "3"
     5) "nova"
     6) "3"
     7) "mini"
     8) "5"
     9) "joey"
    10) "7"
    11) "lex"
    12) "9"
    13) "mason"
    14) "10"
    15) "daniel"
    16) "20"
    17) "david"
    18) "20"
    19) "jane"
    20) "40"
    21) "noah"
    22) "60"
    23) "ted"
    24) "65"
    25) "steve"
    26) "90"
    27) "mike"
    28) "110"
    29) "max"
    30) "500"
    
    // 큰 순서대로 3개 pop
    127.0.0.1:6379> zpopmax users:point 3
    1) "max"
    2) "500"
    3) "mike"
    4) "110"
    5) "steve"
    6) "90"
    
    // 결과 확인
    127.0.0.1:6379> zrange users:point 0 -1 withscores
     1) "leo"
     2) "2"
     3) "lion"
     4) "3"
     5) "nova"
     6) "3"
     7) "mini"
     8) "5"
     9) "joey"
    10) "7"
    11) "lex"
    12) "9"
    13) "mason"
    14) "10"
    15) "daniel"
    16) "20"
    17) "david"
    18) "20"
    19) "jane"
    20) "40"
    21) "noah"
    22) "60"
    23) "ted"
    24) "65"

     

    ZREM, ZREMRANGEBYRANK, ZREMRANGEBYSCORE

    127.0.0.1:6379> help zrem
    
      ZREM key member [member ...]
      summary: Remove one or more members from a sorted set
      since: 1.2.0
      group: sorted_set
    
    127.0.0.1:6379> help zremrangebyrank
    
      ZREMRANGEBYRANK key start stop
      summary: Remove all members in a sorted set within the given indexes
      since: 2.0.0
      group: sorted_set
    
    127.0.0.1:6379> help zremrangebyscore
    
      ZREMRANGEBYSCORE key min max
      summary: Remove all members in a sorted set within the given scores
      since: 1.2.0
      group: sorted_set

    멤버를 삭제하는 명령어들이다. ZREM은 지정한 멤버(들)를 직접 삭제하고, ZREMRANGEBYRANK는 순위의 범위를, ZREMRANGEBYSCORE는 스코어의 범위를 지정하여 멤버를 삭제한다.

    // 한 멤버 삭제하기
    127.0.0.1:6379> zrem users:point ted
    (integer) 1
    
    127.0.0.1:6379> zrange users:point 0 -1 withscores
     1) "leo"
     2) "2"
     3) "lion"
     4) "3"
     5) "nova"
     6) "3"
     7) "mini"
     8) "5"
     9) "joey"
    10) "7"
    11) "lex"
    12) "9"
    13) "mason"
    14) "10"
    15) "daniel"
    16) "20"
    17) "david"
    18) "20"
    19) "jane"
    20) "40"
    21) "noah"
    22) "60"
    
    // 여러 개 삭제하기
    127.0.0.1:6379> zrem users:point noah lex
    (integer) 2
    
    127.0.0.1:6379> zrange users:point 0 -1 withscores
     1) "leo"
     2) "2"
     3) "lion"
     4) "3"
     5) "nova"
     6) "3"
     7) "mini"
     8) "5"
     9) "joey"
    10) "7"
    11) "mason"
    12) "10"
    13) "daniel"
    14) "20"
    15) "david"
    16) "20"
    17) "jane"
    18) "40"
    
    // 순서는 0부터 시작하니까 6, 7등 삭제
    127.0.0.1:6379> zremrangebyrank users:point 5 6
    (integer) 2
    
    127.0.0.1:6379> zrange users:point 0 -1 withscores
     1) "leo"
     2) "2"
     3) "lion"
     4) "3"
     5) "nova"
     6) "3"
     7) "mini"
     8) "5"
     9) "joey"
    10) "7"
    11) "david"
    12) "20"
    13) "jane"
    14) "40"
    
    // score기준 0-10점 사이 데이터 삭제
    127.0.0.1:6379> zremrangebyscore users:point 0 10
    (integer) 5
    
    127.0.0.1:6379> zrange users:point 0 -1 withscores
    1) "david"
    2) "20"
    3) "jane"
    4) "40"

     

    ZINCRBY

    127.0.0.1:6379> help zincrby
    
      ZINCRBY key increment member
      summary: Increment the score of a member in a sorted set
      since: 1.2.0
      group: sorted_set

    스코어를 업데이트 한다.

    // jane에게 20점 추가
    127.0.0.1:6379> zincrby users:point 20 jane
    "40"
    
    // zadd 명령어로 동일 기능 수행 (기존에 daniel 없었으나 추가)
    127.0.0.1:6379> zadd users:point incr 20 daniel
    "20"
    
    // zincrby로 david 추가
    127.0.0.1:6379> zincrby users:point 20 david
    "20"
    
    // 전체 데이터 조회로 확인
    127.0.0.1:6379> zrange users:point 0 -1 withscores
     1) "jason"
     2) "0"
     3) "leo"
     4) "2"
     5) "lion"
     6) "3"
     7) "nova"
     8) "3"
     9) "mini"
    10) "5"
    11) "joey"
    12) "7"
    13) "lex"
    14) "9"
    15) "mason"
    16) "10"
    17) "daniel"
    18) "20"
    19) "david"
    20) "20"
    21) "jane"
    22) "40"
    23) "noah"
    24) "60"
    25) "ted"
    26) "65"
    27) "steve"
    28) "90"
    29) "mike"
    30) "110"
    31) "max"
    32) "500"

     

    ZUNION, ZINTER, ZDIFF

    127.0.0.1:6379> help zunion
    
      ZUNION numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] [WITHSCORES]
      summary: Add multiple sorted sets
      since: 6.2.0
      group: sorted_set
    
    127.0.0.1:6379> help zinter
    
      ZINTER numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] [WITHSCORES]
      summary: Intersect multiple sorted sets
      since: 6.2.0
      group: sorted_set
    
    127.0.0.1:6379> help zdiff
    
      ZDIFF numkeys key [key ...] [WITHSCORES]
      summary: Subtract multiple sorted sets
      since: 6.2.0
      group: sorted_set

    집합연산이긴 하지만, 스코어가 있는 집합연산이다.

    127.0.0.1:6379> zadd zs1 10 A 20 B 30 C
    (integer) 3
    
    127.0.0.1:6379> zadd zs2 40 C 50 D
    (integer) 2
    
    // zs1과 zs2의 합집합
    127.0.0.1:6379> zunion 2 zs1 zs2
    1) "A"
    2) "B"
    3) "D"
    4) "C"
    
    // zs1과 zs2의 합집합 결과와 스코어를 조회
    // 공통 멤버인 C의 점수가 합산되었음
    127.0.0.1:6379> zunion 2 zs1 zs2 withscores
    1) "A"
    2) "10"
    3) "B"
    4) "20"
    5) "D"
    6) "50"
    7) "C"
    8) "70"

    위의 연산은 기본적으로 AGGREGATE SUM이 생략된 셈이다. C멤버의 스코어가 합산되었다. 그런데, AGGREGATE의 옵션을 다른 것으로 변경해 보면 결과가 다르게 노출된다.

    // aggregate sum: 같은 멤버의 경우 스코어 합산
    127.0.0.1:6379> zunion 2 zs1 zs2 withscores aggregate sum
    1) "A"
    2) "10"
    3) "B"
    4) "20"
    5) "D"
    6) "50"
    7) "C"
    8) "70"
    
    // aggregate min: 같은 멤버의 경우 작은 스코어 선택
    127.0.0.1:6379> zunion 2 zs1 zs2 withscores aggregate min
    1) "A"
    2) "10"
    3) "B"
    4) "20"
    5) "C"
    6) "30"
    7) "D"
    8) "50"
    
    // aggregate max: 같은 멤버의 경우 큰 스코어 선택
    127.0.0.1:6379> zunion 2 zs1 zs2 withscores aggregate max
    1) "A"
    2) "10"
    3) "B"
    4) "20"
    5) "C"
    6) "40"
    7) "D"
    8) "50"

    참고로, ZUNION 뒤의 숫자는 몇 개의 키를 입력값으로 사용할 것인지에 대한 숫자이다. 위 명령어 셋에서 공통 적용되는 항목이다. WEIGHTS 옵션은 집합 연산을 행할 때, 스코어에 대한 가중치 부여이다.

    127.0.0.1:6379> zunion 2 zs1 zs2 weights 1 10 withscores aggregate max
    1) "A"
    2) "10"
    3) "B"
    4) "20"
    5) "C"
    6) "400"
    7) "D"
    8) "500"

    zs1의 멤버들은 기존 값 그대로 선택했고, zs2의 멤버들은 x10을 하여 스코어를 환산한 예다. 같은 ZSet으로 이번에는 교집합을 테스트 해보자.

    // 교집합 구하기
    127.0.0.1:6379> zinter 2 zs1 zs2
    1) "C"
    
    // 기본 옵션으로 교집합을 구했을 때 스코어는 aggregate sum과 동일
    127.0.0.1:6379> zinter 2 zs1 zs2 withscores
    1) "C"
    2) "70"
    
    // 교집합 + aggregate max
    127.0.0.1:6379> zinter 2 zs1 zs2 withscores aggregate max
    1) "C"
    2) "40"
    
    // 교집합 + aggregate min
    127.0.0.1:6379> zinter 2 zs1 zs2 withscores aggregate min
    1) "C"
    2) "30"

    차집합을 살펴보자.

    127.0.0.1:6379> zdiff 2 zs1 zs2
    1) "A"
    2) "B"
    
    127.0.0.1:6379> zdiff 2 zs2 zs1
    1) "D"
    
    127.0.0.1:6379> zdiff 2 zs2 zs1 withscores
    1) "D"
    2) "50"

    차를 구하기 때문에, 합집합과 교집합에 있었던 aggregate max/min의 옵션이 없다.

     

    ZUNIONSTORE, ZINTERSTORE, ZDIFFSTORE

    127.0.0.1:6379> help zunionstore
    
      ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
      summary: Add multiple sorted sets and store the resulting sorted set in a new key
      since: 2.0.0
      group: sorted_set
    
    127.0.0.1:6379> help zinterstore
    
      ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
      summary: Intersect multiple sorted sets and store the resulting sorted set in a new key
      since: 2.0.0
      group: sorted_set
    
    127.0.0.1:6379> help zdiffstore
    
      ZDIFFSTORE destination numkeys key [key ...]
      summary: Subtract multiple sorted sets and store the resulting sorted set in a new key
      since: 6.2.0
      group: sorted_set

    실행 결과를 별도로 저장한다는 점이 다를 뿐, 기본적인 동작은 원래 명령어인 ZUNION, ZINTER, ZDIFF와 동일하다.

     

    댓글

    Designed by JB FACTORY