Redis 五种数据类型的简单介绍和使用

1.Redis 特性

  1. 速度快

    正常情况下,Redis 读写性能可以达到 10 万/秒 ;Redis 所有数据是存放在内存中的、Redis 是用 C 语言实现的、Redis 使用了单线程架构。

  2. 基于键值对的数据结构

    Redis 的全称是 REmote Dictionary Server,主要提供了 5 种数据结构:字符串(String)哈希(Hash)列表(List)集合(Set)有序集合(ZSet)

    在字符串的基础上演变出了位图(Bitmaps)HyperLogLog两种数据机构,在 Redis3.2 版本中加入有关GEO(地理信息定位)的功能。

  3. 丰富的功能

    • 提供了键过期功能,可以用来实现缓存
    • 提供了发布订阅功能,可以用来实现消息系统
    • 支持Lua脚本功能,可以利用Lua创造出新的Redis命令
    • 提供了简单的事务功能,能在一定程度上保证事务特性
    • 提供了(Pipeline)功能,这样客户点能将一批命令一次性传到 Redis ,减少了网络的开销
  4. 简单稳定

  5. 客户端语言多

  6. 持久化

    将数据放在内存中是不安全的,一旦发生断电或者机器故障,重要的数据可能就会丢失,因此,Redis 提供了两种持久化方式:RDBAOF,即可以用两种策略将内存的数据保存到硬盘中。

  7. 主从复制

    Redis 提供了复制功能,实现了多个相同数据的 Redis 副本。

  8. 高可用和分布式

    Redis 从2.8版本正式提供了高可用实现 Redis Sentinel,它能够保证 Redis 节点的故障发现和故障自动转移。Redis 从3.0版本正式提供了分布式实现 Redis Cluster,它是 Redis 真正的分布式实现,提供了高可用、读写和容量的扩展性。

2.Redis API的理解与使用

1.全局命令

  • 查看所有键

    keys * 会将所有的键输出

  • 键总数

    dbsize 返回当前数据库中键的总数。 dbsize 命令在计算键总数时不会遍历所有键,而是直接获取Redis 内置的键总数变量,所以dbsize命令的时间复杂度是o(1)。而keys命令会遍历所有键,所以它的时间复杂度是o(n),当Redis中保存了大量键时,线上环境禁止使用

  • 检查键是否存在

    exists key 如果存在则返回1,不存在则返回0。

  • 删除键

    del key [key ...] 返回结果为成功删除键的个数,假设删除一个不存在的键,就会返回0

  • 键过期

    expire key seconds Redis 支持对键添加过期时间,当超过期时间后,会自动删除键。

    ttl key 返回键的剩余过期时间,有3中返回值

    • 大于等于0的整数:键剩余的过期时间
    • -1:键没设置过期时间
    • -2:键不存在
  • 键的数据结构类型

    type key 例如键是字符串类型,返回结果为string,键是列表类型,返回结果为list,如果键不存在,返回 none

2.数据结构和内部编码

type 命令实际返回的是当前键的数据结构类型(5种数据类型),但这些只是Redis对外的数据结构。

实际上每种数据结构都有自己底层的内部编码实现,而且是多种实现,这样Redis会在合适的场景选择合适的内部编码

我们可以通过object encoding key查询内部编码。

Redis 这样设计有2个好处:

  • 可以改进内部编码,而对外的数据结构和命令没有影响,这样一旦开发出更优秀的内部编码,无需改动外部数据结构和命令
  • 多种内部编码实现可以不同场景下发挥各自的优势,例如ziplist比较节省内存,但是在列表元素比较多的情况下,性能会有所下降,这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist

1.字符串

字符串类型是Redis最基础的数据结构。字符串的值最大不能超过512MB

命令

  • 设置值

    set key value [ex seconds] [px milliseconds] [nx|xx]

    • ex seconds:为键设置秒级过期时间
    • px milliseconds:为键设置毫秒级过期时间
    • nx:键必须不存在,才可以设置成功,用于添加
    • xx:与nx相反,键必须存在,才可以设置成功,用于更新

    除了 set 选项,Redis 还提供了 setexsetnx 两个命令,它们的作用和 ex 和 nx 选项是一样的:

    • setex key seconds value
    • setnx key value
  • 获取值

    get key 如果获取的键不存在,则返回nil(空)

  • 批量设置值

    mset key value [key value ...]

  • 批量获取值

    mget key [key ...] 如果有些键不存在,那么它的值为nil(空),结果是按照传入键的顺序返回

  • 计数

    incr key incr命令用于对值做自增的操作,返回结果分为3种情况:

    • 值不是整数,返回错误
    • 值是整数,返回自增后的结果
    • 键不存在,按照值为0自增,返回结果为1

    除了incr命令,Redis提供了decr(自减)incrby(自增指定数字)decrby(自减指定数字)incrbyfloat(自增浮点数)

    • decr key
    • incrby key increment
    • decrby key decrement
    • incrbyfloat key increment
  • 追加值

    append key value append可以向字符串尾部追加值

  • 字符串长度

    strlen key eg:当前值为redisworld,所以返回值为10,当前值为世界,返回值为6(每个中文占用3个字节)

  • 设置并返回原值

    getset key value getset和set一样会设置值,但是不同的是,它同时会返回键原来的值

  • 设置指定位置的字符

    setrange key offset value

    • 下面操作将值由pest变为了best

      127.0.0.1:6379> set redis pest
      OK
      127.0.0.1:6379> setrange redis 0 b
      (integer) 4
      127.0.0.1:6379> get redis
      "best"
      127.0.0.1:6379> setrange redis 2  a
      (integer) 4
      127.0.0.1:6379> get redis
      "beat"
      127.0.0.1:6379> setrange redis 6  c
      (integer) 7
      127.0.0.1:6379> get redis
      "beat\x00\x00c"
      127.0.0.1:6379> 
      
  • 获取部分字符串

    getrange key start end

    start 和 end 分别是开始和结束的偏移量,偏移量从0开始计算

    127.0.0.1:6379> getrange redis 0 1
    "be"
    127.0.0.1:6379> getrange redis 9 10
    ""
    127.0.0.1:6379> getrange redis 4 10
    "\x00\x00c"
    127.0.0.1:6379> getrange redis 3 10
    "t\x00\x00c"
    127.0.0.1:6379> 
    
    命令 时间复杂度
    set key value o(1)
    get key o(1)
    del key [key …] o(k),k是键的个数
    mset key value [key value …] o(k),k是键的个数
    mget key [key …] o(k),k是键的个数
    incr key o(1)
    decr key o(1)
    incrby key increment o(1)
    decrby key increment o(1)
    incrbyfloat key increment o(1)
    append key value o(1)
    strlen key o(1)
    setrange key offset value o(1)
    getrange key start end o(n),n是字符串长度,由于获取字符串非常快,所以如果字符串不是很长,可以视同为o(1)

2.哈希

在 Redis 中,哈希类型是指键值本身又是一个键值对结构。

命令

  • 设置值

    hset key field value

    下面为user:1 添加一对 field-value

    127.0.0.1:6379> hset user:1 name tom
    (integer) 1
    

    如果field已经存在,执行上述命令返回 0,但实际的值发生改变

    127.0.0.1:6379> hset user:1 name ddddd
    (integer) 0
    

    此外,Redis 提供了hsetnx 命令,它们的关系就像set和setnx命令一样,只不过作用域由键变为field

  • 获取值

    hget key field

    下面的操作获取user:1的name域(属性)对应的值,如果键或field不存在,会返回nil

    127.0.0.1:6379> hget user:1  name
    "tom"
    127.0.0.1:6379> hget user:1  namea
    (nil)
    
  • 删除field

    hdel key field [field ...]

    hedl 会删除一个或多个field,返回结果为成功删除field的个数

  • 计算field个数

    hlen key

    例如:user:1 有3个field

    127.0.0.1:6379> hset user:1 name gy
    (integer) 1
    127.0.0.1:6379> hset user:1 age 26
    (integer) 1
    127.0.0.1:6379> hset user:1 city hz
    (integer) 1
    127.0.0.1:6379> hlen user1:1
    (integer) 0  #key不存在返回值
    127.0.0.1:6379> hlen user:1
    (integer) 3
    
  • 批量设置或获取field-value

    hmset key field value [field value ...]

    hmget key field [field...]

    hmset和hmget分别是设置和获取field-value,hmset需要的参数是key和多对field-value,hmget需要的参数是key和多个field。

    127.0.0.1:6379> HMSET user:1 name huang age 12 city xian
    OK
    127.0.0.1:6379> hmget user:1 name age citu city aa
    1) "huang"
    2) "12"
    3) (nil) #field不存在
    4) "xian"
    5) (nil) #field不存在
    
  • 判断field是否存在

    hexists key field

    例如,user:1包含name域,所以返回结果为1,不包含时返回0

    127.0.0.1:6379> HEXISTS user:1 name
    (integer) 1
    127.0.0.1:6379> HEXISTS user:1 name22
    (integer) 0
    127.0.0.1:6379> 
    
  • 获取所有field

    hkeys key

    hkeys命令应该叫hfields更为恰当,他返回指定哈希键所有的field,例如

    127.0.0.1:6379> hkeys user:1
    1) "name"
    2) "age"
    3) "city"
    127.0.0.1:6379> hkeys user:11  #键不存在
    (empty list or set)
    127.0.0.1:6379> 
    
    
  • 获取所有value

    hvals key

    获取 user:1全部value

    127.0.0.1:6379> hvals user:1
    1) "huang"
    2) "12"
    3) "xian"
    127.0.0.1:6379> hvals user:12
    (empty list or set)
    
  • 获取所有的field-value

    hgetall key

    获取user:1所有的field-value

    127.0.0.1:6379> hgetall uset:1 #key不存在的情况
    (empty list or set)
    127.0.0.1:6379> hgetall user:1
    1) "name"
    2) "huang"
    3) "age"
    4) "12"
    5) "city"
    6) "xian"
    127.0.0.1:6379> 
    
    

    在使用 hgetall时,如果哈希元素个数比较多,会存在阻塞 Redis 的可能。如果开发人员只需要获取部分field,可以使用hmget,如果一定要获取全部field-value,可以使用hscan命令,该命令会渐进式遍历哈希类型

  • hincrby hincrbyfloat

    hincrby key field

    hincrbyfloat key field

    就像incrby、incrbyfloat命令一样,但是它们的作用域是field

  • 计算value的字符串长度(需要Redis 3.2以上)

    hstrlen key field

    例如:hget user:1 name 的 value 是 tom,那么hstrlen 的返回结果就是3

    命令 时间复杂度
    hset key field value o(1)
    hget key field o(1)
    hdel key field [field …] o(k),k是field个数
    hlen key o(1)
    hgetall key o(n),n是field总数
    hmget field [field …] o(k),k是field的个数
    hmset field value [field value] o(k),k是field的个数
    hexists key field o(1)
    hkeys key o(n),n是field总数
    hvals key o(n),n是field总数
    hsetnx key field value o(1)
    hincrby key field increment o(1)
    hincrbyfloat key field increment o(1)
    hstrlen key field o(1)

3.列表

列表(list)类型是用来存储多个有序的字符串。列表的每个字符串称为元素(element),一个列表最多可以存储2^32-1个元素。

在 Redis 中,可以对列表两端插入(push)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等。

列表的四种操作类型

操作类型 操作
添加 rpush lpush linsert
查询 lrange lindex llen
删除 lpop rpop lrem ltrim
修改 lset
阻塞操作 bloop brpop
  • 添加操作

    • 从右边插入元素

      rpush key value [value ...]

      下面代码从右向左插入元素c、b、a:

      127.0.0.1:6379> rpush listkey c b a
      (integer) 3
      

      lrange 0 -1命令可以从左到右获取列表所有元素

      127.0.0.1:6379> rpush listkey c b a 
      (integer) 3
      127.0.0.1:6379> lpush listkey e f g #左边插入
      (integer) 6
      127.0.0.1:6379> lrange listkey 0 -1
      1) "g"
      2) "f"
      3) "e"
      4) "c"
      5) "b"
      6) "a"
      127.0.0.1:6379> rrange listkey 0 -1
      (error) ERR unknown command `rrange`, with args beginning with: `listkey`, `0`, `-1`, 
      
    • 从左边插入元素

      lpush key value [value ...]

      使用方法和 rpush 相同,只不过从左侧插入

    • 向某个元素前或者后插入元素

      linsert key before|after pivot value

      linsert 命令会从列表中找到等于 pivot(中枢) 的元素,在其前(before)或者后(after)插入一个 新的元素value。

      下面操作将会在列表的元素b前插入java,返回结果为4,代表当前命令的长度

      127.0.0.1:6379> rpush mylist c b a
      (integer) 3
      127.0.0.1:6379> LRANGE mylist 0 -1
      1) "c"
      2) "b"
      3) "a"
      127.0.0.1:6379> linser mylist before b java
      (error) ERR unknown command `linser`, with args beginning with: `mylist`, `before`, `b`, `java`, 
      127.0.0.1:6379> linsert mylist before b java
      (integer) 4
      127.0.0.1:6379> LRANGE mylist 0 -1
      1) "c"
      2) "java"
      3) "b"
      4) "a"
      
  • 查找

    • 获取指定范围内的元素列表

      lrange key start end

      lrange 操作会获取列表指定索引范围所有的元素。索引下标有两个特点:

      • 索引下标从左到右分别是0到N-1,但是从右到左分别是-1到-N

      • lrange中的 end 选项包含了自身,这个和很多编程语言不包含 end 不太相同,例如像获取列表的第 2 到 第 4 个元素,可以执行如下操作:

        127.0.0.1:6379> lrange mylist 1 3
        1) "java"
        2) "b"
        3) "a"
        127.0.0.1:6379> 
        
        127.0.0.1:6379> lrange mylist 0 1
        1) "c"
        2) "java"
        127.0.0.1:6379> lrange mylist 0 7
        1) "c"
        2) "java"
        3) "b"
        4) "a"
        127.0.0.1:6379> lrange mylist -1 -3
        (empty list or set)
        127.0.0.1:6379> lrange mylist -4 -1
        1) "c"
        2) "java"
        3) "b"
        4) "a"
        127.0.0.1:6379> lrange mylist -5 -1
        1) "c"
        2) "java"
        3) "b"
        4) "a"
        
        
    • 获取列表指定索引下标的元素

      lindex key index

      例如,当前列表最后一个元素为a:

      127.0.0.1:6379> lindex mylist -1
      "a"
      127.0.0.1:6379> lindex mylist 0
      "c"
      127.0.0.1:6379> 
      
    • 获取列表长度

      llen key

      例如,下面表示当前列表长度为4

      127.0.0.1:6379> llen mylist
      (integer) 4
      127.0.0.1:6379> llen mylist2
      (integer) 0  #key值不存在返回的0
      127.0.0.1:6379> 
      
  • 删除

    • 从列表左侧弹出元素

      lpop key

      如下操作将列表最左侧的元素c会被弹出(弹出后,元素被删除),弹出后列表变为 java、b、a:

      127.0.0.1:6379> lrange mylist 0 -1
      1) "c"
      2) "java"
      3) "b"
      4) "a"
      127.0.0.1:6379> lpop mylist
      "c"  #弹出的元素
      127.0.0.1:6379> lrange mylist 0 -1
      1) "java"
      2) "b"
      3) "a"
      
      
    • 从列表右侧弹出

      rpop key

      它的使用方法和lpop是一样的,只不过从列表右侧弹出。

      127.0.0.1:6379> lrange mylist 0 -1
      1) "java"
      2) "b"
      3) "a"
      127.0.0.1:6379> RPOP mylist
      "a"
      
    • 删除指定元素

      lrem key count value

      lrem 命令会从列表中找到等于value的元素进行删除,根据count的不同分为三种情况:

      • count>0,从左到右,删除最多count个元素

      • count<0,从右到左,删除最多count绝对值个元素

      • count=0,删除所有

        例如,向列表从左向右插入5个a,下面操作将从列表左边开始删除4个为a的元素

        127.0.0.1:6379> lpush mylist a a a a a java a 
        (integer) 7
        127.0.0.1:6379> lrange mylist 0 -1
        1) "a"
        2) "java"
        3) "a"
        4) "a"
        5) "a"
        6) "a"
        7) "a"
        127.0.0.1:6379> lrem list 4 a
        (integer) 0
        127.0.0.1:6379> lrem mylist 4 a
        (integer) 4
        127.0.0.1:6379> lrange mylist 0 -1
        1) "java"
        2) "a"
        3) "a"
        
    • 按照索引范围修建列表

      ltrim key start end

      例如,下面操作会只保留列表mylist第2个到第4个元素

      127.0.0.1:6379> lpush mylist a a a a a java a 
      (integer) 7
      127.0.0.1:6379> lrange mylist 0 -1
      1) "a"
      2) "java"
      3) "a"
      4) "a"
      5) "a"
      6) "a"
      7) "a"
      127.0.0.1:6379> ltrim mylist 1 3
      OK
      127.0.0.1:6379> lrange mylist 0 -1
      1) "java"
      2) "a"
      3) "a"
      
  • 修改

    • 修改指定索引下标的元素

      lset key index newValue

      下面操作会将列表listkey中的第3个元素设置为python:

      127.0.0.1:6379> lrange mylist 0 -1
      1) "java"
      2) "a"
      3) "a"
      127.0.0.1:6379> lset mylist 2 python
      OK
      127.0.0.1:6379> lrange mylist 0 -1
      1) "java"
      2) "a"
      3) "python"
      
  • 阻塞操作

    阻塞式弹出如下:

    blpop key [key ...](多个列表的键) timeout(阻塞时间>=0)

    brpop key [key ...] (多个列表的键)timeout(阻塞时间>=0)

    blpop和brpop 是 lpop 和 rpop 的阻塞版本

    • 列表为空:如果timeout=3,那么客服端要等到3秒后返回,如果timeout=0,那么客户端一直阻塞等待下去

      127.0.0.1:6379> brpop list:test 3
      (nil)
      (3.05s)
      127.0.0.1:6379> brpop list:test 0  #命令执行完成后去客户端新增该键值对数据,客户端立即返回
      1) "list:test"
      2) "ggggg"
      (34.77s)
      
      

      列表命令时间复杂度

      操作类型 命令 时间复杂度
      添加 rpush key value [value …] o(k),k是元素的个数
      lpush key value [value …] o(k),k是元素的个数
      linsert key before|after pivot value o(n),n是pivot距离列表头或尾的距离
      查找 lrange key start end o(s+n),s是start偏移量,n是start到end的范围
      lindex key index o(n),n是索引的偏移量
      llen key o(1)
      删除 lpop key o(1)
      rpop key o(1)
      lrem count value o(n),n是列表的长度
      ltrim key start end o(n),n是要裁剪的元素总数
      修改 lset key index value o(n),n是索引的偏移量
      阻塞操作 blpop brpop o(1)

4.集合

集合(set)类型也是用来保存多个的字符串元素,但和列表类型不一样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素。一个集合最多可以存储2^32-1个元素。

Redis除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集。

命令

  • 集合内操作

    • 添加元素

      sadd key member [member ...] 返回结果为添加成功的元素个数。

      127.0.0.1:6379> EXISTS myset
      (integer) 0
      127.0.0.1:6379> sadd myset a b c 
      (integer) 3
      127.0.0.1:6379> sadd myset a b
      (integer) 0
      
    • 删除元素

      srem key member [member ...] 返回结果为成功删除元素的个数

      127.0.0.1:6379> srem myset a b c
      (integer) 3
      127.0.0.1:6379> srem myset hello
      (integer) 0
      
    • 计算元素个数

      scard key scard 的时间复查度为O(1),它不会遍历集合所有元素,而是直接使用 Redis 内部的变量

      127.0.0.1:6379> scard myset
      (integer) 1
      
    • 判断元素是否在集合中

      sismember key element 如果给定元素element在集合内返回1,反之返回0

      127.0.0.1:6379> sismember myset a #不存在
      (integer) 0
      127.0.0.1:6379> sismember myset c
      (integer) 1
      127.0.0.1:6379> sismember myset1 c #不存在
      (integer) 0
      
    • 随机从集合返回指定个数元素

      srandmember key [count] [count]是可选参数,如果不写默认为1

      127.0.0.1:6379> sadd myset a b c 
      (integer) 3
      127.0.0.1:6379> srandmember myset 2
      1) "c"
      2) "a"
      127.0.0.1:6379> srandmember myset 2
      1) "c"
      2) "b"
      127.0.0.1:6379> srandmember myset 2
      1) "a"
      2) "b"
      
    • 从集合随机弹出元素

      spop key [count] spop操作可以从集合中随机弹出一个元素

      srandmember 和 spop 都是随机从集合中选出元素,两者不同的是spop命令执行后,元素会从集合中删除,而srandmember不会

    • 获取所有元素

      smembers key

      127.0.0.1:6379> SMEMBERS myset
      1) "c"
      2) "b"
      

      smembers、lrange、hgetall都属于比较重的命令,如果元素过多存在阻塞Redis的可能性,这时候可以使用sscan来完成。

  • 集合间操作

    • 求多个集合的交集

      sinter key [key ...]

      127.0.0.1:6379> sadd user:1:follow it music his sports
      (integer) 4
      127.0.0.1:6379> sadd user:2:follow it news ent sprots
      (integer) 4
      127.0.0.1:6379> sinter user:1:follow user:2:follow
      1) "it"
      
    • 求多个集合的并集

      sunion key [key ...]

      127.0.0.1:6379> SUNION user:1:follow user:2:follow
      1) "sports"
      2) "it"
      3) "his"
      4) "news"
      5) "ent"
      6) "music"
      7) "sprots"
      
    • 求多个集合的差集

      sdiff key [key ...]

      127.0.0.1:6379> sdiff user:1:follow user:2:follow
      1) "music"
      2) "his"
      3) "sports"
      
    • 将交集、并集、差集的结果保存

      sinterstore destination key [key ...]

      sunionstore destination key [key ...]

      sdiffstore destination key [key ...]

      127.0.0.1:6379> SINTERSTORE user:1_2:inter user:1:follow user:2:follow
      (integer) 1
      127.0.0.1:6379> type user:1_2:inter
      set
      127.0.0.1:6379> SMEMBERS user:1_2:inter
      1) "it"
      

    集合常用命令时间复杂度

    命令 时间复杂度
    sadd key member [member …] O(k),k是元素个数
    srem key member [member …] O(k),k是元素个数
    scard key O(1)
    sismember key member O(1)
    srandmember key [count] O(count)
    spop key O(1)
    smembers key O(n),n是元素总数
    sinter key [key …] || sinterstore O(m*k),k是多个集合中元素最少的个数,m是键个数
    sunion key [key …] || sunionstore O(k),k是多个集合元素个数和
    sdiff key [key …] || sdiffstore O(k),k是多个集合元素个数和

5.有序集合

它保留了集合不能有重复成员的特性,增加了有序集合的元素可以排序。但是它和列表使用索引下标作为排序依据不同的是,它给每个元素设置一个分数(score)作为培训的依据。

列表、集合、有序集合三者的异同点

数据结构 是否允许重复元素 是否有序 有序实现方式 应用场景
列表 索引下标 时间轴、消息队列等
集合 标签、社交等
有序集合 分值(score) 排行榜系统、社交等

命令

  • 集合内

    • 添加成员

      zadd key score member [score member ...]

      127.0.0.1:6379> zadd user:ranking 251 tom
      (integer) 1
      127.0.0.1:6379> zadd user:ranking 251 tom
      (integer) 0 #返回结果代表成功添加成员的个数
      

      有关zadd命令有2点需要注意:

      Redis 3.2 为 zadd 命令添加了nx、xx、ch、incr四个选项

      • nx:member必须不存在,才可以设置成功,用于添加
      • xx:member必须存在,才可以设置成功,用于更新
      • ch:返回此次操作后,有序集合元素和分数发生变化的个数
      • incr:对score做增加,相当于后面介绍的zincrby

      有序集合相比集合提供了排序字段,但是也产生了代价,zadd的时间复杂度为O(log(n)),sadd的时间复杂度为O(1)。

    • 计算成员个数

      zcard key

    • 计算某个成员的分数

      zscore key member

      127.0.0.1:6379> ZSCORE user:ranking tom
      "252"
      127.0.0.1:6379> ZSCORE user:ranking tomss
      (nil)  #如果成员不存在返回nil
      
    • 计算成员的排名

      zrank key member 分数低到高返回排名(排序从0开始计算)

      zrevrank key member 分数从高到低返回排名(排序从0开始计算)

    • 删除成员

      zrem key member [member...]

      127.0.0.1:6379> zrem user:ranking mike
      (integer) 1 #返回结果为成功删除的个数
      
    • 增加成员的分数

      zincrby key increment member

      127.0.0.1:6379> zscore user:ranking tom
      "252"  #当前数据库中的分数
      127.0.0.1:6379> zincrby user:ranking 8 tom
      "260" #增加8分后返回的结果
      
    • 返回指定排名范围的成员

      zrange key start end [withscores]

      zrevrange key start end [withscores]

      有序集合是按照分值排名的,zrange是从低到高返回,zrevrange反之。

      如果加上 withscores选项,同时会返回成员的分数:

      127.0.0.1:6379> ZRANGE  user:ranking 0 2   #返回排名最低的3个成员
      1) "kris"
      2) "frank"
      3) "tim"
      127.0.0.1:6379> ZRANGE  user:ranking 0 2 withscores
      1) "kris"
      2) "1"
      3) "frank"
      4) "200"
      5) "tim"
      6) "220"
      127.0.0.1:6379> ZREVRANGE  user:ranking 0 2 withscores
      1) "tom"
      2) "260"
      3) "tom3"
      4) "252"
      5) "martin"
      6) "250"
      
    • 返回指定分数范围的成员

      zrangebyscore key min max [withscores] [limit offset count]

      zrevrangebyscore key max min [withscores] [limit offset count]

      zrangebyscore 按照分数从低到高返回,zrevrangebyscore反之。

      withscores 会同时返回每个成员的分数

      limit offset count 选项可以限制输出的起始位置和个数

      min和max 支持开区间(小括号)和闭区间(中括号),-inf 和 +inf 分别代表无限小和无限大

      127.0.0.1:6379> ZRANGEBYSCORE user:ranking 200 +inf withscores
       1) "frank"
       2) "200"
       3) "tim"
       4) "220"
       5) "martin"
       6) "250"
       7) "tom3"
       8) "252"
       9) "tom"
      10) "260"
      127.0.0.1:6379> ZRANGEBYSCORE user:ranking 200 +inf withscores limit 2 4
      1) "martin"
      2) "250"
      3) "tom3"
      4) "252"
      5) "tom"
      6) "260"
      
    • 返回指定分数范围成员个数

      zcount key min max

    • 删除指定排名内的升序元素

      zremrangebyrank key start end

      127.0.0.1:6379> ZREMRANGEBYRANK user:ranking 0 2
      (integer) 3  #删除前3个元素
      
    • 删除指定分数范围的成员

      zremrangebyscore key min max

      127.0.0.1:6379> ZREMRANGEBYSCORE user:ranking (250 +inf  #将250分以上的成员全部删除,返回结果为成功删除的个数
      (integer) 2
      
  • 集合间的操作

    • 交集

      zinterstore destination numkeys key [key ...] [weights weight] [aggregate sum|min|max]

      • destination:交集计算结果保存到这个键
      • numkeys:需要做交集计算键的个数
      • key[key…]:需要做交集计算的键
      • weights weight:每个键的权重,在做交集计算时,每个键中的每个member会将自己分数乘以这个权重,每个键的权重默认是1。
      • aggregate sum|min|max:计算成员交集后,分值按照sum(和)、min(最小值)、max(最大值)做汇总,默认值是sum。

      下面将对user:ranking:1和user:ranking:2做交集,weights和aggregate使用了默认值,可以看到目标键user:ranking:1_inter_2对分值做了sum操作

      127.0.0.1:6379> zadd user:ranking:1 1 kris 91 mike 200 frank 220 tim 250 martin 251 tom
      (integer) 6
      127.0.0.1:6379> zadd user:ranking:2 8 james 77 mike 625 martin 888 tom
      (integer) 4
      127.0.0.1:6379> ZINTERSTORE user:ranking:1_inter_2 2 user:ranking:1 user:ranking:2 
      (integer) 3
      127.0.0.1:6379> zrange user:ranking:1_inter_2 0 -1 withscores
      1) "mike"
      2) "168"
      3) "martin"
      4) "875"
      5) "tom"
      6) "1139"
      

      如果想让user:ranking:2的权重变为0.5,并且聚合效果使用max,可以执行如下操作:

      127.0.0.1:6379> ZINTERSTORE user:ranking:1_inter_2 2 user:ranking:1 user:ranking:2 weights 1 0.5 aggregate max
      (integer) 3
      127.0.0.1:6379> zrange user:ranking:1_inter_2 0 -1 withscores
      1) "mike"
      2) "91"
      3) "martin"
      4) "312.5"
      5) "tom"
      6) "444"
      
    • 并集

      zunionstore destination numkeys key [key ...] [weights weight] [aggregate sum|min|max]

    有序集合命令的时间复杂度

    命令 时间复杂度
    zadd key score member [score member …] O(kxlog(n)),k是添加成员的个数,n是当前有序集合成员个数
    zcard key O(1)
    zscore key member O(1)
    zrank/zrevrank key member O(log(n)),n是当前有序集合成员个数
    zrem key member [member …] O(k*log(n)),k是删除成员的个数,n是当前有序集合成员个数
    zincrby key increment member O(log(n)),n是当前有序集合成员个数
    zrange/zrevrange key start end [withscores] O(log(n)+k),k是要获取的成员个数,n是当前有序集合成员个数
    zrangebyscore/zrevrangebyscore key min/max max/min [withscores] O(log(n)+k),k是要获取的成员个数,n是当前有序集合成员个数
    zcount key min max O(log(n)),n是当前有序集合成员个数
    zremrangebyrank key start end O(log(n)+k),k是要删除的成员个数,n是当前有序集合成员个数
    zremrangebyscore key min max O(log(n)+k),k是要删除的成员个数,n是当前有序集合成员个数
    zinterstore destination numkeys key [key …] O(nxk)+O(mxlog(m)),n是成员数量最小的有序集合成员个数,k是有序集合的个数,m是结果集中成员个数
    zunionstore destination numkeys key [key …] O(n)+O(mxlog(m)),n是所有有序集合成员个数和,m是结果集中成员个数
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章