Redis 자료 구조 - Set

개요

프로그래밍 언어에서 어떨 때 set을 사용할까? 주로 중복을 제거하거나, 말 그대로 집합 연산(포함여부 및 합집합/교집합 등)을 해야할 경우에 사용할 것이다. Redis에서도 이러한 연산을 지원한다.

 

명령어

Redis가 지원하는 집합 연산 기능은 아래와 같다.

 

SADD

127.0.0.1:6379> help sadd

  SADD key member [member ...]
  summary: Add one or more members to a set
  since: 1.0.0
  group: set

set에 아이템을 추가한다.

// 여러 아이템을 set에 추가
127.0.0.1:6379> sadd s1 e1 e2 e3
(integer) 3

127.0.0.1:6379> smembers s1
1) "e2"
2) "e3"
3) "e1"

// 이미 추가된 아이템을 다시 추가시도 -> 변화 없음
127.0.0.1:6379> sadd s1 e1
(integer) 0

 

SREM

127.0.0.1:6379> help srem

  SREM key member [member ...]
  summary: Remove one or more members from a set
  since: 1.0.0
  group: set

지정한 요소(들)를 set에서 삭제한다. 여러 개의 요소도 지울 수 있다. 없는 요소가 지정되면 무시한다.

127.0.0.1:6379> sadd s1 e1 e2 e3
(integer) 3

127.0.0.1:6379> smembers s1
1) "e2"
2) "e3"
3) "e1"

// 요소 한 개 지우기
127.0.0.1:6379> srem s1 e1
(integer) 1
127.0.0.1:6379> smembers s1
1) "e2"
2) "e3"

// 요소 여러 개 지우기 (없는 요소도 지정해 봄)
127.0.0.1:6379> srem s1 e1 e2 e3
(integer) 2
127.0.0.1:6379> smembers s1
(empty array)

 

SCARD

127.0.0.1:6379> help scard

  SCARD key
  summary: Get the number of members in a set
  since: 1.0.0
  group: set

set에 들어가 있는 아이템 갯수(cardinality)를 리턴한다.

// 여러 아이템을 set에 추가
127.0.0.1:6379> sadd s1 e1 e2 e3
(integer) 3

// 갯수 확인
127.0.0.1:6379> scard s1
(integer) 3

 

SISMEMBER

127.0.0.1:6379> help sismember

  SISMEMBER key member
  summary: Determine if a given value is a member of a set
  since: 1.0.0
  group: set

set에 포함된 요소인지 검사한다.

// 여러 아이템을 set에 추가
127.0.0.1:6379> sadd s1 e1 e2 e3
(integer) 3

// s1에 e1이 포함되어 있는지 확인
127.0.0.1:6379> sismember s1 e1
(integer) 1

// s1에 e2가 포함되어 있는지 확인
127.0.0.1:6379> sismember s1 e5
(integer) 0

 

SMEMBERS

127.0.0.1:6379> help smembers

  SMEMBERS key
  summary: Get all the members in a set
  since: 1.0.0
  group: set

set에 들어가 있는 모든 아이템들을 조회한다.

// 여러 아이템을 set에 추가
127.0.0.1:6379> sadd s1 e1 e2 e3
(integer) 3

127.0.0.1:6379> smembers s1
1) "e2"
2) "e3"
3) "e1"

모든 아이템을 조회하므로, set에 들어가 있는 아이템의 크기에 따라 성능의 영향을 받을 수 있다. 운영환경에서 전체 데이터를 가져와야 하면 SSCAN을 사용하자.

 

SSCAN

127.0.0.1:6379> help sscan

  SSCAN key cursor [MATCH pattern] [COUNT count]
  summary: Incrementally iterate Set elements
  since: 2.8.0
  group: set

keys가 전체 데이터를 긁어와서 장애를 일으킬 수 있기 때문에 scan을 써야 하는 것과 같이, 집합에서도 전체 members를 가져올 때 사용한다. 분할해서 가져오는 방식이기 때문에 여러번 호출해 줘야 한다.

// 전체 데이터
127.0.0.1:6379> smembers s_all
 1) "e3"
 2) "e2"
 3) "e7"
 4) "e5"
 5) "e4"
 6) "e9"
 7) "e10"
 8) "e6"
 9) "e1"
10) "e8"

// 두 개씩 가져오기
127.0.0.1:6379> sscan s_all 0 count 2
1) "2"
2) 1) "e2"
   2) "e7"
127.0.0.1:6379> sscan s_all 2 count 2
1) "5"
2) 1) "e5"
   2) "e4"
   3) "e9"
127.0.0.1:6379> sscan s_all 5 count 2
1) "7"
2) 1) "e8"
   2) "e10"
   3) "e6"
   4) "e1"
127.0.0.1:6379> sscan s_all 7 count 2
1) "0"
2) 1) "e3"

1)에 리턴되는 것이 명령을 수행한 후의 커서이다. 즉, 다음 페이지는 저 커서부터 실행하면 된다. count에 숫자를 부여했지만, 저 숫자를 엄격하게 보장해주지는 않는다. 위의 결과에서 보다시피, count로 2를 줬지만 2개를 주기도 4개를 주기도 한다. 커서가 0이 리턴되면 모든 데이터를 다 가져왔다는 즉 다음 페이지가 없다는 의미이다. 즉, 커서를 기반으로 로직을 작성한다면 커서가 0이 리턴될 때까지 반복해야 한다는 뜻이다.

127.0.0.1:6379> sscan s_all 0 match e1* count 10
1) "0"
2) 1) "e10"
   2) "e1"

위와 같이 match 조건을 추가적으로 부여할 수도 있다.

 

SMOVE

127.0.0.1:6379> help smove

  SMOVE source destination member
  summary: Move a member from one set to another
  since: 1.0.0
  group: set

말 그대로, 집합내 어떤 요소를 다른 집합으로 옮기는 기능이다.

// e12는 짝수인데, 실수로 s_odd에 넣었다.
127.0.0.1:6379> sadd s_odd e12
(integer) 1

127.0.0.1:6379> smembers s_odd
1) "e9"
2) "e1"
3) "e12"
4) "e7"
5) "e5"
6) "e3"

// e12를 원래대로 짝수 집합으로 옮기고 싶다.
127.0.0.1:6379> smove s_odd s_even e12
(integer) 1

// 홀수 집합에서 e12가 사라짐
127.0.0.1:6379> smembers s_odd
1) "e9"
2) "e1"
3) "e7"
4) "e5"
5) "e3"

// 짝수 집합에 e12가 추가됨
127.0.0.1:6379> smembers s_even
1) "e8"
2) "e4"
3) "e6"
4) "e2"
5) "e10"
6) "e12"

 

SRANDMEMBER

127.0.0.1:6379> help srandmember

  SRANDMEMBER key [count]
  summary: Get one or multiple random members from a set
  since: 1.0.0
  group: set

set에서 count 만큼의 요소를 무작위로 가져온다.

127.0.0.1:6379> sadd s1 e1 e2 e3
(integer) 3

// 2개 요소 가져옴
127.0.0.1:6379> srandmember s1 2
1) "e1"
2) "e3"

// 원본 set에는 변화 없음
127.0.0.1:6379> smembers s1
1) "e2"
2) "e3"
3) "e1"

원본 set의 상태에는 변화가 없다. count를 생략하면 기본적으로 count = 1로 간주한다. 음수로 지정해도 동작하는데 양수를 넣은 것과 큰 차이는 없다.

// count 생략시
127.0.0.1:6379> srandmember s1
"e1"
127.0.0.1:6379> srandmember s1
"e3"

// count를 음수로 지정시
127.0.0.1:6379> srandmember s1 -1
1) "e3"
127.0.0.1:6379> srandmember s1 -2
1) "e2"
2) "e3"
127.0.0.1:6379> srandmember s1 -3
1) "e3"
2) "e3"
3) "e1"

 

SPOP

127.0.0.1:6379> help spop

  SPOP key [count]
  summary: Remove and return one or multiple random members from a set
  since: 1.0.0
  group: set

SRANDMEMBER와 비슷하지만, 차이점은 실행 후의 액션이다. SRANDMEMBER는 조회만 하지만, SPOP은 해당 요소를 삭제한다. SRANDMEMBER가 peek이라면, SPOP은 이름처럼 pop을 해버린다.

// count를 지정하지 않으먼, 1로 간주
127.0.0.1:6379> spop s1
"e1"

// 1개 요소가 사라짐
127.0.0.1:6379> smembers s1
1) "e2"
2) "e3"

// 두 개 요소만 있는 상태에서, 5개를 지우라고 함
127.0.0.1:6379> spop s1 5
1) "e2"
2) "e3"

// 모두 지워지고 빈 set이 됨
127.0.0.1:6379> smembers s1
(empty array)

 

SUNION, SINTER, SDIFF

127.0.0.1:6379> help sunion

  SUNION key [key ...]
  summary: Add multiple sets
  since: 1.0.0
  group: set

127.0.0.1:6379> help sinter

  SINTER key [key ...]
  summary: Intersect multiple sets
  since: 1.0.0
  group: set

127.0.0.1:6379> help sdiff

  SDIFF key [key ...]
  summary: Subtract multiple sets
  since: 1.0.0
  group: set

합집합 연산부터 살펴본다.

// 편의상 e[1,3,5,7,9] = 홀수집합이라고 표현
// 편의상 e[2,4,6,8,19] = 짝수집합이라고 표현

// 홀수 집합 
127.0.0.1:6379> smembers s_odd
1) "e7"
2) "e5"
3) "e3"
4) "e1"
5) "e9"

// 짝수 집합
127.0.0.1:6379> smembers s_even
1) "e2"
2) "e8"
3) "e4"
4) "e6"
5) "e10"

// 홀수 + 짝수 합집합
127.0.0.1:6379> sunion s_odd s_even
 1) "e4"
 2) "e9"
 3) "e1"
 4) "e7"
 5) "e8"
 6) "e5"
 7) "e3"
 8) "e2"
 9) "e10"
10) "e6"

교집합은 아래와 같다.

// 전체
127.0.0.1:6379> smembers s_all
 1) "e3"
 2) "e2"
 3) "e7"
 4) "e5"
 5) "e4"
 6) "e9"
 7) "e10"
 8) "e6"
 9) "e1"
10) "e8"

// 부분
127.0.0.1:6379> smembers s_odd
1) "e7"
2) "e5"
3) "e3"
4) "e1"
5) "e9"

// 전체와 부분의 교집합
127.0.0.1:6379> sinter s_all s_odd
1) "e7"
2) "e5"
3) "e3"
4) "e1"
5) "e9"

차집합의 예는 아래와 같다.

// 전체
127.0.0.1:6379> smembers s_all
 1) "e3"
 2) "e2"
 3) "e7"
 4) "e5"
 5) "e4"
 6) "e9"
 7) "e10"
 8) "e6"
 9) "e1"
10) "e8"

// 부분
127.0.0.1:6379> smembers s_odd
1) "e7"
2) "e5"
3) "e3"
4) "e1"
5) "e9"

// 전체 - 부분
127.0.0.1:6379> sdiff s_all s_odd
1) "e2"
2) "e4"
3) "e6"
4) "e10"
5) "e8"

 

SUNIONSTORE, SINTERSTORE, SDIFFSTORE

127.0.0.1:6379> help sunionstore

  SUNIONSTORE destination key [key ...]
  summary: Add multiple sets and store the resulting set in a key
  since: 1.0.0
  group: set

127.0.0.1:6379> help sinterstore

  SINTERSTORE destination key [key ...]
  summary: Intersect multiple sets and store the resulting set in a key
  since: 1.0.0
  group: set

127.0.0.1:6379> help sdiffstore

  SDIFFSTORE destination key [key ...]
  summary: Subtract multiple sets and store the resulting set in a key
  since: 1.0.0
  group: set

위에서 수행한 집합 연산 결과를 또다른 집합(set)으로 저장하고 싶다면, 이 명령어를 쓴다.

// s_even과 s_odd를 합쳐서 s_all로 만들기
127.0.0.1:6379> sunionstore s_all s_even s_odd
(integer) 10

127.0.0.1:6379> smembers s_all
 1) "e4"
 2) "e6"
 3) "e10"
 4) "e7"
 5) "e8"
 6) "e5"
 7) "e3"
 8) "e2"
 9) "e9"
10) "e1"

교집합과 차집합도 동일하다. 명령어 output input1 input2 .. 의 형식을 그대로 따른다.

 

'Development > Hadoop, NoSQL, BigData' 카테고리의 다른 글

Redis pub/sub 소개  (2) 2021.06.17
Redis Geo - Geospatial 명령어  (0) 2021.06.07
Redis 자료 구조 - ZSet (Sorted Set)  (0) 2021.06.02
Redis 자료 구조 - Hash  (0) 2021.05.27
Redis 자료 구조 - List  (0) 2021.05.10
Redis 자료 구조 - String  (0) 2021.05.06
Memcached vs. Redis - 특징 비교  (0) 2021.05.03
Redis 개요  (0) 2021.04.28

Designed by JB FACTORY