Redis 避不开的五种数据结构--sortset

有序集合类型

看名字我们就知道,有序集合也是一种集合,并且这个集合还是有序的。列表也是有序的,那它和有序集合又有什么不同呢?有序集合的有序和列表的有序是不同的。列表中的有序指的的是插入元素的顺序和查询元素的顺序相同,而有序集合中的有序指的是它会为每个元素设置一个分数(score),而查询时可以通过分数计算元素的排名,然后再返回结果。因为有序集合也是集合类型,所以有序集合中也是不插入重复元素的,但在有序集合中分数则是可以重复,那如果在有序集合中有多个元素的分数是相同的,这些重复元素的排名是怎么计算的呢?后边我们再做详细说明。

下面先看一下列表、集合、有序集合三种数据类型之间的区别:

数据结构

是否允许重复元素

是否有序

有序实现方式

应用场景

列表

索引下标

时间轴、消息队列

集合

标签、社交

有序集合

分数

排行榜、社交

命令

1.集合内操作

  • 添加元素
zadd key [NX|XX] [CH] [INCR] score member [score member ...]

zadd 命令也是有返回值的,返回值就是当前 zadd 命令成功添加元素的个数。zadd 命令有很多选填参数:

  • nx: 元素必须不存在时,才可以设置成功。
  • xx: 元素必须存在时,才可以设置成功。
  • ch: 返回此命令执行完成后,有序集合元素和分数发生变化的个数
  • incr: 对 score 做增加。

备注:由于有序集合相比集合提供了排序字段,正是因为如此也付出了相应的代价,sadd 的时间复杂度为 O(1),而 zadd 的时间复杂度为O(log(n))。

  • 计算成员个数
zcard key

  • 计算某个成员的分数
zscore key member

在使用 zscore 命令时,如果 key 不存在,或者元素不存在时,该命令返回的都是(nil)。

  • 计算成员的排名
zrank key member
zrevrank key member

zrank 命令是从分数低到高排名,而 zrevrank 命令则恰恰相反,从高到低排名。有一点要特别注意, zrank 和 zrevrank 命令与 zscore 是命令不同的,前者通过分数计算出最后的排名,而后者则是直接返回当前元素的分数。

  • 删除元素
zrem key member [member ...]

返回的结果为成功删除元素的个数,因为 zrem 命令是支持批量删除的。

  • 增加元素分数
zincrby key increment member

虽然 zincrby 命令是增加元素分数的,但我们也可以指定负数,这样当前元素的分数,则会相减。

  • 返回指定排名范围的元素
zrange key start stop [WITHSCORES]
zrevrange key start stop [WITHSCORES]

zrange 命令是通过分数从低到高返回数据,而 zrevrange 命令是通过分数从高到低返回数据。如果执行命令时添加了 WITHSCORES 可选参数,则返回数据时会返回当前元素的分数。

  • 返回指定分数范围的元素
zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
zrevrangebyscore key max min [WITHSCORES] [LIMIT offset count]

min 和 max 参数还支持开区间(小括号)和闭区间(中括号),同时我们还可以用 -inf 和 +inf 参数代表无限小和无限大。

  • 返回指定分数范围元素个数
zcount key min max

  • 删除指定排名内的升序元素
zremrangebyrank key start stop

  • 删除指定分数范围元素
zremrangebyscore key min max

2.集合间操作

  • 交集
zinterstore destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]

zinterstore 命令参数比较多:

  • destination:将交集的计算结果,保存到这个键中。
  • numkeys:需要做交集计算键的个数。
  • key [key ...]:需要做交集计算的键。
  • WEIGHTS weight:每个键的权重,在做交集计算时,每个键中的分数值都会乘以这个权重,默认每个键的权重为 1。
  • AGGREGATE SUM|MIN|MAX:计算成员交集后,分值可以按照 sum(和)、min(最小值)、max(最大值)做汇总,默认值为  sum。

下面我们将权重设置为 0.5,这样当计算交集后,有序集合中的元素分数将都会减半,并且使用 max 参数汇总。

  • 并集
zunionstore destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]

zunionstore 命令的相关参数和 zinterstore 命令相同。

内部编码

有序集合类型的内部编码有两种,它们分别是:

  • ziplist(压缩列表):当有序集合的元素个数小于 128 个(默认设置),同时每个元素的值都小于 64 字节(默认设置),Redis 会采用 ziplist 作为有序集合的内部实现。
  • skiplist(跳跃表):当上述条件不满足时,Redis 会采用 skiplist 作为内部编码。

备注:上述中的默认值,也可以通过以下参数设置:zset-max-ziplist-entries 和 zset-max-ziplist-value。

下面我们用以下示例来验证上述结论。

当元素个数比较少,并且每个元素也比较小时,内部编码为 ziplist:

当元素个数超过 128 时,内部编码为 skiplist。下面我们将采用 python 动态创建128个元素,下面为源码:

import redis

r = redis.Redis(host='127.0.0.1', port=6379)
if r.object('encoding', 'zsetkey') != None:
    print('Key为【zsetkey】的字节编码为【%s】' % r.object('encoding', 'zsetkey').decode('utf-8'))
for i in range(1, 600):
    r.zadd('zsetkey',i,1)
if r.object('encoding', 'zsetkey') != None:
    print('Key为【zsetkey】的字节编码为【%s】' % r.object('encoding', 'zsetkey').decode('utf-8'))
Key为【zsetkey】的字节编码为【ziplist】
Key为【zsetkey】的字节编码为【skiplist】

当有序集合中有任何一个元素大于 64 个字节时,内部编码为 skiplist。

import redis

r = redis.Redis(host='127.0.0.1', port=6379)
if r.object('encoding', 'zsetkey') != None:
    print('Key为【zsetkey】的字节编码为【%s】' % r.object('encoding', 'zsetkey').decode('utf-8'))
value = ''
for i in range(1, 600):
    value += str(i)
r.zadd('zsetkey',value,1)
if r.object('encoding', 'zsetkey') != None:
    print('Key为【zsetkey】的字节编码为【%s】' % r.object('encoding', 'zsetkey').decode('utf-8'))
Key为【zsetkey】的字节编码为【skiplist】

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值