Redis - Set


이 포스트는 Redis 의 데이터 타입 중 하나인 Set 타입에 대해 알아본다.

  • Set
    • SADD
    • SMEMBERS
    • SCARD
    • SISMEMBER
    • SREM
    • SSCAN
    • SMOVE
    • SRANDMEMBER
    • SPOP
    • SUNION, SINTER, SDIFF
    • SUNIONSTORE, SINTERSTORE, SDIFFSTORE
    • SINTERCARD

1. Set

  • List 가 하나의 key 에 여러 개의 배열값을 저장하는 데이터 구조라고 하면 Set 은 배열 구조가 아닌 여러 개의 member 로 데이터 값을 표현하는 데이터 구조
  • 중복을 제거하거나, 집합 연산 (포함여부 및 합집합, 교집합 등) 을 해야할 경우에 사용
$ pwd
/usr/local/opt/redis/bin

$ brew services start redis
==> Successfully started `redis` (label: homebrew.mxcl.redis)

$ redis-cli
127.0.0.1:6379>

1.1. 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
127.0.0.1:6379> sadd set1 e1 e2 e3
(integer) 3

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

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

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

127.0.0.1:6379> sadd set1 e2  # 이미 추가된 element 는 추가해도 변화없음
(integer) 0

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

1.2. SMEMBERS

set 안의 모든 member 를 조회하는 명령어이다.

127.0.0.1:6379> help smembers

  SMEMBERS key
  summary: Get all the members in a set
  since: 1.0.0
  group: set
127.0.0.1:6379> smembers set1
1) "e2"
2) "e1"
3) "e3"

1.3. SCARD

set 에 있는 member 갯수를 조회하는 명령어이다.

127.0.0.1:6379> help scard

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

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

127.0.0.1:6379> scard set1
(integer) 3

1.4. SISMEMBER

set 안에 해당 member 가 존재하는지 여부를 조회한다.

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

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

127.0.0.1:6379> sismember set1 e1
(integer) 1

127.0.0.1:6379> sismember set1 99
(integer) 0

1.5. 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
127.0.0.1:6379> sadd set1 e1 e2 e3 e4
(integer) 4

127.0.0.1:6379> smembers set1
1) "e2"
2) "e1"
3) "e4"
4) "e3"

127.0.0.1:6379> srem set1 e1 e2 e9 e2  # e9 는 없는 member 이지만 오류를 뱉지 않는다. 
(integer) 2

127.0.0.1:6379> smembers set1
1) "e4"
2) "e3"

127.0.0.1:6379> smembers set99
(empty array)

127.0.0.1:6379> srem set99 e4  # set99 는 존재하지 않는 set 이지만 오류를 뱉지 않는다.
(integer) 0

1.6. SSCAN

keys 는 전체 데이터를 조회해서 장애를 일으킬 수 있다.
성능을 위해 Hash 에서도 keys 대신 HSCAN 을 사용하는 것처럼 Set 에서도 전체 members 를 조회할 때 SSCAN 을 사용한다.

HSCAN 에 대한 내용은 Redis - Hash 의 2.11. HSCAN 을 참고하세요.

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

아래에서 1) 에 리턴되는 것이 명령을 수행한 후의 커서이다.
다음 호출은 해당 커서부터 실행하면 된다.

count 에 2를 부여했지만 4개, 3개가 리턴되기도 한다.
커서가 0 을 리턴하면 모든 데이터를 다 가져왔다는 의미이므로 커서 기반으로 로직 작성 시 커서가 0 이 될때까지 반복하면 된다.

127.0.0.1:6379> sadd set1 e1 e2 e3 e4 e5 e6 e7 e8 e9 e10
(integer) 10

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

127.0.0.1:6379> sscan set1 0 count 2
1) "6"
2) 1) "e9"
   2) "e3"
   3) "e6"
   4) "e5"

127.0.0.1:6379> sscan set1 6 count 2
1) "1"
2) 1) "e7"
   2) "e4"

127.0.0.1:6379> sscan set1 1 count 2
1) "3"
2) 1) "e1"
   2) "e2"
   3) "e10"

127.0.0.1:6379> sscan set1 3 count 2
1) "0"
2) 1) "e8"
127.0.0.1:6379> sadd set1 e1 e2 e3 e4 e5 e6 e7 e8 e9 e10
(integer) 10

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

127.0.0.1:6379> sscan set1 0 match e1* count 10
1) "7"
2) 1) "e1"
   2) "e10"
   
127.0.0.1:6379> sscan set1 7 match e1* count 10
1) "0"
2) (empty array)

SCAN 명령어는 싱글 스레드 아키텍처에서 keyssmembers 가 가진 문제점을 해결하는 명령어이지만 아래와 같은 문제점도 있으니 주의하자.

  • scan 의 경우 table 의 한 블럭을 조회하기 때문에 갯수가 많으면 시간이 오래 걸릴 수 있음
  • set / sorted set / hash 의 내부 구조가 hash table 이나 skiplist 가 아니면 (ziplist 로 구현된 경우) 한 컬렉션의 모든 데이터를 가져오기 때문에 keys 와 비슷한 문제가 그대로 발생할 수 있음
  • count 옵션을 지정할 수 있지만 그 갯수를 엄격하게 보장해주지 않음 (=count 를 2로 해도 4개 리턴해주기도 함)

1.7. SMOVE

source set 에서 destination set 으로 member 를 이동시키는 명령어이다.

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
127.0.0.1:6379> sadd set1 e1 e2
(integer) 2
127.0.0.1:6379> sadd set2 e3 e4
(integer) 2

127.0.0.1:6379> smembers set1
1) "e2"
2) "e1"
127.0.0.1:6379> smembers set2
1) "e4"
2) "e3"

127.0.0.1:6379> smove set1 set2 e1  # set1 의 member 를 set2 로 이동시킨다.
(integer) 1
127.0.0.1:6379> smembers set1
1) "e2"
127.0.0.1:6379> smembers set2
1) "e1"
2) "e4"
3) "e3"

127.0.0.1:6379> smove set1 set3 e2 # set1 의 member 를 존재하지 않는 set3 으로 이동시킨다.
(integer) 1
127.0.0.1:6379> smembers set1
(empty array)
127.0.0.1:6379> smembers set3  # set3 이 생성되었다.
1) "e2"

127.0.0.1:6379> smembers set2
1) "e1"
2) "e4"
3) "e3"
127.0.0.1:6379> smembers set3
1) "e2"

127.0.0.1:6379> smove set2 set3 e9  # set2 에 존재하지 않는 member 인 e9 를 set3 으로 이동시키면 아무런 변화가 없다.
(integer) 0
127.0.0.1:6379> smembers set2
1) "e1"
2) "e4"
3) "e3"
127.0.0.1:6379> smembers set3
1) "e2"

1.8. SRANDMEMBER

set 에서 랜덤하게 count 수만틈 member 를 조회한다.
count 를 지정하지 않으면 랜덤으로 1개를 조회하고, count 를 0 으로 지정하면 빈 배열을 리턴한다.

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
127.0.0.1:6379> sadd set1 e1 e2 e3 e4 e5
(integer) 5
127.0.0.1:6379> smembers set1
1) "e2"
2) "e1"
3) "e4"
4) "e3"
5) "e5"

127.0.0.1:6379> srandmember set1
"e3"

127.0.0.1:6379> srandmember set1 0
(empty array)

127.0.0.1:6379> srandmember set1 3
1) "e5"
2) "e3"
3) "e2"

127.0.0.1:6379> srandmember set1 3
1) "e1"
2) "e5"
3) "e3"

1.9. SPOP

SRANDMEMBER 와 동일하게 count 갯수만큼 member 를 조회하지만 조회 후 해당 member 를 삭제한다.
SRANDMEMBER - peek, SPOP - pop

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
127.0.0.1:6379> smembers set1
1) "e1"
2) "e3"
3) "e5"
4) "e2"
5) "e4"

127.0.0.1:6379> spop set1
"e3"

127.0.0.1:6379> smembers set1
1) "e1"
2) "e5"
3) "e2"
4) "e4"

127.0.0.1:6379> spop set1 2
1) "e4"
2) "e2"

127.0.0.1:6379> smembers set1
1) "e1"
2) "e5"

127.0.0.1:6379> spop set1 5
1) "e1"
2) "e5"

127.0.0.1:6379> smembers set1
(empty array)

1.10. SUNION, SINTER, SDIFF

  • 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

SUNION

127.0.0.1:6379> sadd set1 e1 e2
(integer) 2
127.0.0.1:6379> sadd set2 e3 e4
(integer) 2

127.0.0.1:6379> smembers set1
1) "e2"
2) "e1"
127.0.0.1:6379> smembers set2
1) "e4"
2) "e3"

127.0.0.1:6379> sunion set1 set2
1) "e1"
2) "e2"
3) "e3"
4) "e4"

127.0.0.1:6379> smembers set1
1) "e2"
2) "e1"

SINTER

127.0.0.1:6379> smembers set1
1) "e2"
2) "e1"
127.0.0.1:6379> smembers set2
1) "e4"
2) "e3"

127.0.0.1:6379> sinter set1 set2
(empty array)

127.0.0.1:6379> sadd set1 e3
(integer) 1
127.0.0.1:6379> smembers set1
1) "e2"
2) "e1"
3) "e3"
127.0.0.1:6379> smembers set2
1) "e4"
2) "e3"

127.0.0.1:6379> sinter set1 set2
1) "e3"

SDIFF

127.0.0.1:6379> smembers set1
1) "e2"
2) "e1"
3) "e3"
127.0.0.1:6379> smembers set2
1) "e4"
2) "e3"

127.0.0.1:6379> sdiff set1 set2
1) "e1"
2) "e2"

127.0.0.1:6379> sdiff set2 set1
1) "e4"

1.11. SUNIONSTORE, SINTERSTORE, SDIFFSTORE

SUNION, SINTER, SDIFF 로 수행한 결과를 새로운 set 으로 저장할 때 사용하는 명령어이다.

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
127.0.0.1:6379> sadd set1 e1 e2 e3
(integer) 3
127.0.0.1:6379> sadd set2 e4 e5 e2 e3
(integer) 4
127.0.0.1:6379> smembers set1
1) "e3"
2) "e1"
3) "e2"
127.0.0.1:6379> smembers set2
1) "e3"
2) "e4"
3) "e5"
4) "e2"

127.0.0.1:6379> sunionstore set_all
(error) ERR wrong number of arguments for 'sunionstore' command

127.0.0.1:6379> sunionstore set_all set1  # set1 만 union 하여 set_all 로 저장
(integer) 3
127.0.0.1:6379> smembers set_all
1) "e3"
2) "e1"
3) "e2"
127.0.0.1:6379> smembers set1
1) "e3"
2) "e1"
3) "e2"

127.0.0.1:6379> sunionstore set_all set1 set2  # set1, set2 를 union 하여 set_all 로 저장
(integer) 5
127.0.0.1:6379> smembers set_all
1) "e4"
2) "e1"
3) "e2"
4) "e5"
5) "e3"
127.0.0.1:6379> smembers set1
1) "e3"
2) "e1"
3) "e2"

127.0.0.1:6379> sunionstore set_all set1 set3  # set1 과 존재하지 않는 set3 을 union 하여 set_all 로 저장
(integer) 3
127.0.0.1:6379> smembers set_all  # set1 만 union 되어 set_all 로 저장된다.
1) "e3"
2) "e1"
3) "e2"

1.12. SINTERCARD

여러 set 의 교집합을 한 후 해당되는 member 의 갯수를 리턴한다.

127.0.0.1:6379> help sintercard

  SINTERCARD numkeys key [key ...] [LIMIT limit]
  summary: Intersect multiple sets and return the cardinality of the result
  since: 7.0.0
  group: set
127.0.0.1:6379> sadd set1 e1 e2 e3
(integer) 3
127.0.0.1:6379> sadd set2 e2 e3 e4
(integer) 3

127.0.0.1:6379> sintercard 2 set1 set2  # e2, e3
(integer) 2
127.0.0.1:6379> smembers set1
1) "e3"
2) "e1"
3) "e2"

127.0.0.1:6379> sadd set1 e4
(integer) 1
127.0.0.1:6379> smembers set1
1) "e3"
2) "e4"
3) "e1"
4) "e2"

127.0.0.1:6379> sintercard 2 set1 set2  # e2, e3, e4
(integer) 3

127.0.0.1:6379> sintercard 1 set1 set2  # numkeys 가 1 인데 연산되는 set 의 갯수가 2개라 오류 발생
(error) ERR syntax error

127.0.0.1:6379> sintercard 3 set1 set2  # numkeys 가 3 인데 연산되는 set 의 갯수가 2개라 오류 발생
(error) ERR Number of keys can't be greater than number of args

참고 사이트 & 함께 보면 좋은 사이트

본 포스트는 주종면 저자의 빅데이터 저장 및 분석을 위한 NoSQL & Redis를 기반으로 스터디하며 정리한 내용들입니다.






© 2020.08. by assu10

Powered by assu10