暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis值类型之set

并发编程之美 2020-08-12
247

介绍

在集合中的每个元素都是不同的,且没有顺序。集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在等,由于集合类型在Redis内部是使用值为空的散列表(hash table)实现的,所以这些操作的时间复杂度都是 0(1)。最方便的是多个集合类型键之间还可以进行并集、交集和差集运算,一个集合类型键可以存储至多2^32-1个字符串。


一、集合类型特点

特点:

  • 无序:集合类型的无序体现在底层实现是hash表,随着添加的东西变多,会rehash扩容,这时遍历的时候顺序就会变化。所以集合无序是在某一个场景下数据量发生变化的时候,之前看的顺序与现在的就不一样了,和放入顺序也无关

  • 无重复

  • 集合间操作


二、应用场景

集合类型适用的场景就是随机事件。


场景一:抽奖系统

  • spop或者srandmember进行弹出


场景二:like,点赞数,踩


场景三:用户标签

  • 给用户添加标签:

    sadd user:1:tags tag1 tag2 tag5
    sadd user:2:tags tag1 tag3 tag5
    ......
    • 给标签添加用户:

      sadd tag:1:user user:1 user:3
      sadd tag:2:user user:2 user:3 user:5
      .....

      上面两个操作是同一个事务处理。


      场景四:集合间操作

      • 共同关注,共同好友


      三、命令拾遗

        127.0.0.1:6379> help @set


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


        127.0.0.1:6379>

        命令演示

        1. SADD(增加元素)和SREM(删除元素)

        SADD命令用来向集合中增加一个或多个元素,如果键不存在则会自动创建。如果要加入的元素已经存在于集合中就会忽略这个元素。返回值是成功加入的元素数量。

          127.0.0.1:6379> sadd k1 a
          (integer) 1
          127.0.0.1:6379> sadd k1 a b c
          (integer) 2

          SREM命令用来从集合中删除一个或多个元素,并返回删除成功的个数。

            127.0.0.1:6379> srem k1 c d
            (integer) 1


            2. SMEMBERS(获取集合中所有元素)

              127.0.0.1:6379> smembers k1
              1)"b"
              2)"a"

              集合中元素非常多时谨慎使用。可以借助扫描游标处理。


              3. SISMEMBER(判断元素是否在集合中)

              判断一个元素是否在集合中是一个时间复杂度为0(1)的操作,无论集合中有多少个元素,SISMEMBER命令始终可以极快地返回结果。当值存在时SISMEMBER命令返回1,当值不存在或键不存在时返回0。

                127.0.0.1:6379> sismember k1 a
                (integer) 1
                127.0.0.1:6379> sismember k1 d
                (integer) 0


                4. SDIFF(差集)SINTER(交集)SUNION(并集)

                集合A与集合B的差集表示为A-B,代表所有属于A且不属于B的元素构成的集合。

                  127.0.0.1:6379> sadd setA 1 2 3
                  (integer) 3
                  127.0.0.1:6379> sadd setA 2 3 4
                  (integer) 3
                  127.0.0.1:6379> sdiff setA setB
                  1)"1"
                  127.0.0.1:6379> sdiff setB setA
                  1)"4"
                  127.0.0.1:6379> sadd setC 2 3
                  (integer) 2
                  127.0.0.1:6379> sdiff setA setB setC
                  1)"1

                  SDIFF 命令支持同时传入多个键,计算顺序是先计算A-B,在计算结果与setC的差集。

                  集合A与集合B的交集代表所有属于A且属于B的元素构成的集合。

                    127.0.0.1:6379> sinter setA setB setC
                    1)"2"
                    2)"3"

                    集合A与集合B的并集代表所有属于A或属于B的元素构成的集合。

                      127.0.0.1:6379> sunion setA setB setC
                      1)"1"
                      2)"2"
                      3)"3"
                      4)"4"

                      SDIFFSTORE命令和SDIFF命令功能一样,唯一的区别就是前者不会直接返回运算结果,而是将结果存储在destination键中。


                      SDIFFSTORE命令常用于需要进行多步集合运算的场景中,如需要先计算差集再将结果和其他键计算交集。 


                      SINTERSTORE和SUNIONSTORE命令与之类似。

                      可以用于推荐系统

                      • 共同好友:并集

                      • 推荐好友:差集


                      5. SCARD(获取集合中元素个数)

                        127.0.0.1:6379> smembers k1
                        1)"a"
                        2)"b"
                        3)"c"
                        4)"d"
                        127.0.0.1:6379> scard k1
                        (integer) 4


                        6. SRANDMEMBER(随机获取集合中元素)

                          127.0.0.1:6379> srandmember k1
                          1)"a"
                          127.0.0.1:6379> srandmember k1
                          1)"b"
                          127.0.0.1:6379> srandmember k1
                          1)"a"

                          还可以传递count参数来一次随机获得多个元素,根据count的正负不同,具体表现也不同。

                            127.0.0.1:6379> smembers k1
                            1)"a"
                            2)"b"
                            3)"c"
                            4)"d"
                            127.0.0.1:6379> srandmember k1 2
                            1)"a"
                            2)"c"
                            127.0.0.1:6379> srandmember k1 2
                            1)"a"
                            2)"b"
                            127.0.0.1:6379> srandmember k1 100
                            1)"b"
                            2)"a"
                            3)"c"
                            4)"d"
                            127.0.0.1:6379> srandmember k1 -2
                            1)"b"
                            2)"b"
                            127.0.0.1:6379> srandmember k1 -10
                            1)"b"
                            2)"b"
                            3)"c"
                            4)"c"
                            5)"b"
                            6)"a"
                            7)"b"
                            8)"d"
                            9)"b"
                            10)"b"
                            • SRANDMEMBER:正数不会重复,大于元素个数返回全部元素

                            • SRANDMEMBER:负数有可能重复,大于元素个数则进行填充(可能集合有的元素不出现)

                            • 可以用于抽奖


                            从结果中可以很明显地看出b元素出现的次数相对较,出现这种情况是由集合类型采用的存储结构是散列表造成的。散列表使用散列函数将元素映射到不同的存储位置(桶)上以实现0(1)时间复杂度的元素查找。当使用散列表存储元素b时,使用散列函数计算出b的散列值是0,所以将b存入编号为0的桶(bucket)中, 下次要查找b时就可以用同样的散列函数再次计算b的散列值并直接到相应的桶中找到b。当两个不同的元素的散列值相同时会出现冲突,Redis使用拉链法来解决冲突,即将散列值冲突的元素以链表的形式存入同一桶中,查找元素时先找到元素对应的桶,然后再从桶中的链表中找到对应的元素。使用SRANDMEMBER命令从集合中获得一个随机元素时,Redis首先会从所有桶中随机选择一个桶,然后再从桶中的所有元素中随机选择一个元素,所以元素所在的桶中的元素数量越少,被随机选中的可能性就越大,如下:

                            7. SPOP(从集合随机弹出一个元素)

                            由于集合类型的元素是无序的,所以SPOP命令会从集合中随机选择一个元素弹出。

                              127.0.0.1:6379> spop k1
                              "b"
                              127.0.0.1:6379> smembers k1
                              1)"a"
                              2)"c"
                              3)"d"


                              四、集合总结

                              集合类型和列表类型对比:


                              集合类型列表类型
                              存储内容至多2^32-1个字符串
                              至多2^32-1个字符串
                              有序性

                              唯一性

                              TIPS

                              • SADD = Tagging

                              • SPOP/SRANDMEMBER = Random item

                              • SADD + SINTER = Social Graph


                              推荐阅读

                              Redis开篇介绍

                              Redis值类型之string

                              Redis值类型之list

                              Redis值类型之hash

                              看完本文有收获?请转发分享给更多人

                              关注「并发编程之美」,一起交流Java学习心得

                              文章转载自并发编程之美,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                              评论