redis学习笔记(三):列表、集合、有序集合

使用理解基本API

redis提供了5种数据结构,理解每次数据结构的特色在开发和运维中是很重要的.使用redis版本:3.0.7javascript

本章内容以下:java

  1. redis列表redis

  2. redis集合shell

  3. redis有序集合数据结构

1.1 列表

列表(list)类型是用来存储多个字符串,以下图A,B,C,D四个元素从左到右组成一个有序的集合.列表中的每一个字符串被称为元素(element),一个列表最多能够存储(2的32次方)-1个元素.在redis中,能够对列表两端插入(push)和弹出(pop),还能够获取指定范围的元素列表、获取指定全部下标的元素等.app

列表

列表类型有两个特色:负载均衡

  1. 列表中的元素是有序的,这就意味着能够经过索引下标获取某个元素或者某个范围内的元素列表.运维

  2. 列表中的元素能够是重复的.编码

1.1.1 命令

1) 插入命令

(1) 从右边插入元素.spa

rpush key value [value...]

例:
向列表插入a,b,c三个元素.
从右边插入元素

lrange key 0 -1命令能够获取列表中全部的元素.

获取全部元素

(2) 从左边插入元素.
使用方法与rpush同样,从左侧插入.

lpush key value [value....]

例:
从左边插入元素

2) 查询命令

(1) 查询指定范围内的元素列表

lrange key start end

lrange操做会获取列表指定索引范围全部的元素.索引下标有两个特色:第一,索引下标从左到右分别是0N-1,可是从右到左分别是-1-N.第二,lrange中的end选项包含了自身.
例:
查询指定范围内的元素列表

(2) 获取列表指定索引下的元素

lindex key index

例:

获取列表指定索引下的元素

(3) 获取列表长度

llen key

例:

获取列表长度

3) 删除命令

(1) 从列表左侧或右侧弹出元素.

以下操做是将列表最左侧与右侧的元素弹出来.

从列表左侧或右侧弹出元素

(2) 删除指定元素

lrem key count value

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

  1. count>0,从列表中删除指定数量(count)的元素.

  2. count<0,从列表中删除count绝对值数量的元素.

  3. count=0,删除全部.
    例:

指定元素数量:
删除指定元素数量

全部元素:
删除全部元素

(3) 按照索引范围修剪列表

ltrim key start end

例如,下面操做会保留列表第二个到第六个元素:

按照索引范围修剪列表

4)修改命令

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

lset key index value

例:
修改第一个元素的值为c.
修改指定索引下标的元素

4) 阻塞操做

阻塞式弹出:

blpop key [key...] timeout
    brpop key [key...] timeout

blpopbrpop命令是lpoprpop命令的阻塞版本,他除了弹出方向不一样,使用方法基本相同,因此下面以brpop命令进行说明,brpop命令包含两个参数:

  • key [key...]:多个列表的键.

  • timeout:阻塞时间(单位为).

1)列表为空:若是timeout等于3,那么客户端等到三秒后返回,若是timeout=0,那么客户端将一直阻塞,直到弹出成功.

列表为空

2)列表不为空:客户端会马上返回.

列表不为空

在使用阻塞弹出命令时,有两点须要注意.

第一点:若是是多个键,那么会从左到右遍历键,一旦有一个键能弹出元素客户端就会马上返回.
第二点:若是多个客户端同时对一个键进行操做,那么最早执行命令的客户端能够获取到值.

1.1.2 内部编码

列表类型的内部编码有两种:

编码名 编码描述
ziplist(压缩列表) 当列表的元素个数大于list-max-ziplist-entries配置(默认为512个),同时列表中每一个元素的长度小于list-max-ziplist-value配置(默认为64字节).
linkedlist(链表) 当列表的长度或值得大小不知足ziplist的要求,redis会采用linkedlist为列表的内部实现编码.

1.1.3 使用场景

  1. 消息队列:redislpush-brpop命令组合便可实现阻塞队列,生产者客户端使用lpush命令向列表插入元素.消费者客户端使用brpop命令阻塞式的"抢"列表中的尾部元素.多个客户端保证消息的负载均衡与可用性.
    clipboard.png

  2. 文章列表:每一个用户都有属于本身的文章列表.此时能够考虑使用列表,由于列表不可是有序的,同时支持使用lrange按照索引范围获取多个元素.
    伪代码:

var articles = redis.lrange('user:1:acticles',0,9);
    articles.forEach(function(){
        // 遍历操做
    });

开发提示:列表的使用场景有不少如: lpush+lpop=Stack(栈)、lpush+rpop=queue(队列)、lpush+brpop=message queue(消息队列)、lpush+ltrim=Capped Collection(有限集合)

1.2 集合

集合(set)类型也是用来保存多个的字符串元素,但和列表不一样的是:它的元素是无序且不可重复的,不能经过索引获取元素.以下图,集合user:1:follows中包含着"his"、"it"、"sports"、"music"四个元素,一个集合最多能够存储(2的32次方-1)个元素.
clipboard.png

1.2.1 命令

1) 集合内操做

(1) 添加元素

sadd key value [value...]

返回结果为添加成功的元素数量.
例:

添加元素

(2) 删除元素

srem key value [value...]

返回结果为删除成功的元素数量.
例:

删除元素

(3) 获取元素个数

scard key

例:

获取元素个数

(4) 判断元素是否在集合中

sismember key value

若是元素存在于集合内则返回1,反之返回0.
例:

判断元素是否在集合中

(5) 随机从集合中返回指定个数元素

srandmember key [count]

[count]是可选参数,若是不写默认为:1.
例:

随机从集合中返回指定个数元素

(6) 从集合中随机弹出元素

spop key

spop操做能够从集合中随机弹出一个元素.

例:
从集合中随机弹出元素
使用spop命令后,集合元素变为"1","3".

(7) 获取集合的全部元素

smembers key

获取集合全部元素,且返回结果是无序的.

获取集合的全部元素

2) 集合间操做

(1) 求多个集合的交集

sinter key [key...]

例:

求多个集合的交集

(2) 求多个集合的并集

sunion key [key...]

例:

求多个集合的并集

(3) 求多个集合的差集

sdiff key [key...]

例:

求多个集合的差集

(4) 将交集、并集、差集的结果保存.

sinterstore storeKey key [key...]
    sunionstore storeKey key [key...]
    sdiffstore storeKey key [key...]

集合间的运算在元素比较多的状况下会比较耗时,因此redis提供了上面三个命令(原命令+store)将集合间交集、并集、差集的结果保存到storeKey中,例如将user:1:followsuser:2:follows两个集合之间的交集结果保存到user:1_2:follows中.
交集保存

1.2.2 内部编码

集合类型的内部编码有两种:

编码名 编码描述
intset(整数集合) 当集合中的元素全是整数,且长度不超过set-max-intset-entries(默认为512个)时,redis会选用intset做为内部编码.
hashtable(哈希表) 当集合没法知足intset的条件时,redis会使用hashtable做为内部编码.

1.2.3 使用场景

集合类型比较典型的使用场景是标签(tag).例如一个用户可能对音乐感兴趣,另外一个用户对新闻感兴趣,这些想去点就是标签.有了这些数据就能够得到喜欢同一个标签的人,以及用户的共同喜爱的标签,这些数据对于用户体验来讲比较重要.

下面使用集合类型实现标签功能的若干功能.例如:

(1) 给用户添加标签:
给用户添加标签

(2) 给标签添加用户:
给标签添加用户

(3) 删除用户的标签:
删除用户的标签

(4) 删除标签的用户:
删除标签的用户
34最好在同一个事务下进行处理.

(5) 计算用户共同拥有的标签:
clipboard.png

1.3 有序集合

有序集合相对于哈希、列表、集合来讲会有一点陌生,但既然叫有序集合.那么它和集合必然是有着联系,它保留了集合不能重复元素的特性.但不一样的是,有序集合是可排序的.可是他和列表使用索引下标进行排序依据不一样的是,它给每一个元素设置一个分数(score)做为排序的依据.
clipboard.png

列表、集合、有序结合的异同点

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

1.3.1 命令

1)集合内

(1) 添加成员

zadd key score member [score member ...]

下面操做向有序集合user:ranking增长用户Rico和他的分数60分:

添加成员

有关zadd命令有两点须要注意:

  • Redis 3.2zadd命令添加了nxxxchincr四个选项:

    • nx:member必须不存在,才能够设置成功,用于添加.

    • xx:member必须存在,才能够设置成功,用于添加.

    • ch:返回这次操做后,有序结合元素和分数发生变化的个数.

    • incr: 对score进行添加操做,至关于后面介绍的zincrby.

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

(2) 获取成员个数

zcard key

例:
clipboard.png

(3) 获取某个成员的分数

zscore key member

例:
获取某个成员的分数

(4) 获取成员排名

zrank key member
    zrevrank key member

zrank命令是从分数从低到高返回排名,zrevrank反之,排名从0开始.例以下面:

计算成员的排名

(5) 删除成员

zrem key member [member...]

下面操做成员ann从有序集合user:ranking中删除.

删除成员

(6) 增长成员分数

zincrby key score member

下面操做给Rico成员添加9分,分数变为69分.

增长成员分数

(7) 获取制定范围的元素

zrange key start end [withscores] 
    zrevrange key start end [withscores]

有序集合是按照分值排名的,zrange是由低到高返回,zrevrange反之,查询所有:zrange user:ranking 0 -1,加上withscores参数显示分数.
例:
获取前三名.

127.0.0.1:6379> zrange user:ranking 0 2
    1) "codger"
    2) "hank"
    3) "ann"
    127.0.0.1:6379> zrevrange user:ranking 0 2
    1) "tom"
    2) "Rico"
    3) "ann"

(8) 返回指定分数范围的成员

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

例:
返回分数在0100的成员.

127.0.0.1:6379> zrangebyscore user:ranking 0 100
    1) "codger"
    2) "hank"
    3) "ann"
    4) "Rico"
    5) "tom"

返回分数在0到无限大的成员.

127.0.0.1:6379> zrangebyscore user:ranking 0 +inf
    1) "codger"
    2) "hank"
    3) "ann"
    4) "Rico"
    5) "tom"

同时minmax还支持开区间(小括号)和闭区间(中括号),-inf+inf分别表明无限小和无限大:

127.0.0.1:6379> zrangebyscore user:ranking (10 +inf withscores
    1) "hank"
    2) "15"
    3) "ann"
    4) "30"
    5) "Rico"
    6) "69"
    7) "tom"
    8) "80"

(9) 返回指定分数范围成员个数

zcount key min max

下面返回分数为1015的成员:

127.0.0.1:6379> zcount user:ranking (10 15
    (integer) 1

(10) 删除指定排名内的升序元素

zremrangebyrank key start end

删除第start到第end名的成员:

127.0.0.1:6379> zremrangebyrank user:ranking 0 1
    (integer) 2

(11) 删除指定分数范围的成员

zremrangebyscore key min max

删除分数从minmax的成员:

127.0.0.1:6379> zremrangebyscore user:ranking 0 30
    (integer) 1

2) 集合间的操做

(1) 交集

zinterstore storeKey keyNum key [key ...] [weights weight [weight...]] [aggregate sum|min|max]

参数说明:

  • storeKey:交集计算结果保存到这个键下.

  • keyNum:须要作交集的键的个数.

  • key[key ...]:须要作交集的键.

  • weights weight [weight...]:每一个键的权重,在作交集计算时,每一个键中的每一个member的分值会和这个权重相乘,每一个键的权重默认为1.

  • aggregate sum|min|sum:计算成员交集后,分值能够按照sum(和)、min(最小值)、max(最大值)作汇总.默认值为sum.

127.0.0.1:6379> zrange user:ranking:2 0 -1 withscores
    1) "Rico"
    2) "138"
    3) "tom"
    4) "160"
    127.0.0.1:6379> zinterstore user:ranking:1_2 2 user:ranking user:ranking:2 aggregate min
    (integer) 2
    127.0.0.1:6379> zrange user:ranking:1_2 0 -1
    1) "Rico"
    2) "tom"
    127.0.0.1:6379> zrange user:ranking:1_2 0 -1 withscores
    1) "Rico"
    2) "69"
    3) "tom"
    4) "80"

(2) 并集

zunionstore storeKey keyNum key [key...] [weights weight [weight...]] [aggregate sum|min|max]

该命令的全部参数和zinterstore是一致的,只不过作的是并集计算.
例:

127.0.0.1:6379> zunionstore user:ranking:1_2 2 user:ranking user:ranking:2  aggregate min
    (integer) 3
    127.0.0.1:6379> zrange user:ranking:1_2 0 -1 withscores
    1) "Rico"
    2) "69"
    3) "codger"
    4) "90"
    5) "tom"
    6) "160"

1.3.2 内部编码

编码名称 编码描述
ziplist(压缩列表) 当有序集合的元素小于zset-max-ziplist-entries配置(默认是128个),同时每一个元素的值都小于zset-max-ziplist-value(默认是64字节)时,Redis会用ziplist来做为有序集合的内部编码实现,ziplist能够有效的减小内存的使用
skiplist(跳跃表) ziplist的条件不知足时,有序集合将使用skiplist做为内部编码的实现,来解决此时ziplist形成的读写效率降低的问题.
相关文章
相关标签/搜索