在家做兼职官方网站平台,网站与app的本质区别,友情链接怎么设置,商城网站合同zset是Redis的有序集合数据类型#xff0c;但是其和set一样是不能重复的。但是相比于set其又是有序的。set的每个数据都有一个double类型的分数#xff0c;zset正是根据这个分数来进行数据间的排序从小到大。有序集合中的元素是唯一的#xff0c;但是分数(score)是可以重复的…zset是Redis的有序集合数据类型但是其和set一样是不能重复的。但是相比于set其又是有序的。set的每个数据都有一个double类型的分数zset正是根据这个分数来进行数据间的排序从小到大。有序集合中的元素是唯一的但是分数(score)是可以重复的。每个zset集合最多可以存放232-1个数据。zset常被用于排行榜功能。
1、常用命令
zadd key score1 member1 [score2 member2]向有序集合中添加一个或多个数据或者更新已存在成员的分数(member会先删除在重新插入)。zcard key获取集合的数据个数。zcount key min max计算集合中在指定分数区间内的数据个数。zincrby key increment member在集合指定成员的分数加上增量increment。increment为负数表示减去相应的值。zinterstore destination numberkeys key [key…]计算给定的一个或者多个集合的交集并将结果存储到destination中。结果集中某个成员的分数是所有给定的集合该成员所有分数的和。zlexcount key min max在有序集合中计算指定字典区间内的成员数量。zrange key start end[withscores]通过索引区间返回指定区间内的成员。zrangebylex key min max[limit offset count]通过字典区间返回有序集合的成员。zrangebyscore key min max[withscores][limit]通过分数返回集合中的成员。zrank key member返回有序集合中指定成员的索引。zrem key member [memeber…]删除集合中一个或者多个成员。zremrangebylex key min max移出集合中指定字典区间内的所有成员。zremrangebyrank key start stop移出有序集合中给定的排名区间内的所有成员。zrevrange key start end[withscores]返回指定索引区间内的成员分数从高到低。zrevrangebyscore key max min[withscores]返回集合中指定分数区间内的成员分数从高到低。zrevrank key member返回集合中指定成员的排名。0表示最高。zscore key member返回集合中指定成员的分数。zunionstore destination numberkeys key [key…]计算给定的一个或者多个集合的并集并存储在destination中。zscan key cursor[match pattern][COUNT count]迭代集合的元素。
2、底层实现
zset的底层实现有两种ziplist和dictskiplist。
2.1、ziplist
2.1.1、使用条件
集合中元素数量小于128个。每个元素的长度小于64字节。
以上两个条件有任何一个不满足就会使用dictskiplist的结构存储数据。 每个集合元素使用紧挨着的两个压缩列表节点保存第一个节点保存元素的成员第二个保存元素的分数。
2.1.2、ziplist结构
见Hash中的ziplist
2.2、dictskiplist
2.2.1、介绍
dict用来存储value到score的映射关系这样就可以在O(1)时间内找到对应value的score值。skiplist按照从小到大的顺序存储分数。skiplist每个元素的值都是[score,value]对。
2.2.2、zset结构
typedf struct zset{//字典键为value值为scoredict* dict;//跳表按分值进行排序zskiplist *zsl;
}zset;typedf struct zskiplist{//头节点struct zskiplistNode *header;//尾节点struct zskiplistNode *tail;//跳表中的元素个数unsigned long length;//目前表内节点最高的层数int level;
}zskiplist;zskiplist的示意图如下
typedf struct zskiplistNode{//具体的数据sds ele;//分数double size;//后退指针struct zskiplistNode *backward;struct zskiplistLevel{//前进指针struct zskiplistNode *forward;/跨服unsigned int span;}level[]; //层数数组 最大32
}zskiplistNode;skiplistNode的示意图如下
2.2.3、skiplist-跳表
跳表skiplist在Redis中的使用场景只有一个那就是作为zset的底层结构实现。跳表可以保证增、删、查的时间复杂度为O(logN)其余一般的链表结构的时间复杂度为O(n)相比性能上有不少的提升。但是唯一美中不足的是跳表需要占用更多的空间其实这就是一种空间换时间的思想。跳表的结构如下 Redis中的跳表的实现有点类似于Kafka中的稀疏索引。 在Kafka中进行持久化的时候会生成两个文件一个是xxxxxx.log一个是xxxxxx.index其中log文件中以链表的方式保存着消息。而index文件中则保存着这些消息的索引或者说是偏移量但又不是每一条消息的索引都在index文件中。index中的索引是稀疏的比如log文件中的索引是0-10000那么index文件中存储的索引可能是100500700100050006500每个索引中都保存着对应log文件中消息的具体位置。如图 当要访问899这个索引的消息时先去index文件中查找找到了700到1000的这个区间根据700这个索引去log文件中找到700这个索引的消息然后顺着700这个消息顺序往下找直到找到899这个索引的消息。从这个实现中我们看到Kafka并没有对log文件进行全部的遍历而是先通过index中的稀疏索引找到一个大概的位置然后顺序遍历。 Redis的跳表的实现方式与上面的类似不过Kafka的稀疏索引只有一层而Redis的稀疏索引是多层。如图 所有的元素都会在L0层的链表中根据分数进行排序同时会有一部分节点被抽取到L1层作为一个稀疏索引同样L1层的索引也有一定的机会被抽取到L2层以此类推Redis允许跳表中一个节点最高有**64层**一个跳表中最多存储264 个元素。
2.2.4、跳表-增、删、查
首先假定有这么一个跳表这里只展示分数 如果要查找分数为66的元素首先在L2层的索引查找。很明显。66位于25和85之间 然后根据获得的区间去对应的L1的区间查找得到一个更精确的区间 最终根据更精确的区间去L0层顺序遍历即可找到要查找的元素 上述即是对跳表原理的一个描述。 这种跳表的实现其实和二分查找的思路接近只是一方面因为二分查找法只能适用与数组而无法用于链表所以为了让链表有二分查找类似的效率就以空间换时间来达到目的。 跳表因为是一个根据分数权重进行排序的列表可以在很多场景中使用比如排行榜搜索排序等。