Redis 有序集合(Sorted Set)

news2025/4/22 7:29:38

Redis 有序集合(Sorted Set)

以下从基础命令内部编码使用场景三个维度对 Redis 有序集合进行详细解析:


一、基础命令

命令时间复杂度命令含义
zadd key score member [score member …] O ( k × l o g ( n ) ) O(k×log(n)) O(k×log(n)),k是添加成员的个数,n是当前有序集合成员个数向有序集合(Sorted Set)中添加一个或多个成员,同时为每个成员关联一个分数(score),根据分数对成员进行排序 。
zcard keyO(1)获取有序集合中成员的数量 。
zscore key memberO(1)获取有序集合中指定成员的分数 。
zrank key memberO(log(n)),n是当前有序集合成员个数获取有序集合中指定成员的排名(从0开始,按分数从小到大排序) 。
zrevrank key memberO(log(n)),n是当前有序集合成员个数获取有序集合中指定成员的排名(从0开始,按分数从大到小排序) 。
zrem key member [member …]O(k*log(n)),k是删除成员的个数,n是当前有序集合成员个数从有序集合中删除一个或多个成员 。
zincrby key increment memberO(log(n)),n是当前有序集合成员个数为有序集合中指定成员的分数加上指定的增量 。
zrange key start end [withscores]O(log(n)+k),k是要获取的成员个数,n是当前有序集合成员个数按照分数从小到大的顺序,获取有序集合中指定区间内的成员,可选择是否返回成员的分数 。
zrevrange key start end [withscores]O(log(n)+k),k是要获取的成员个数,n是当前有序集合成员个数按照分数从大到小的顺序,获取有序集合中指定区间内的成员,可选择是否返回成员的分数 。
zrangebyscore key min max [withscores] [limit offset count]O(log(n)+k),k是要获取的成员个数,n是当前有序集合成员个数按照分数范围,获取有序集合中分数在指定区间内的成员,可选择是否返回成员的分数,还可通过limit指定返回结果的偏移量和数量 。
zrevrangebyscore key max min [withscores] [limit offset count]O(log(n)+k),k是要获取的成员个数,n是当前有序集合成员个数按照分数范围,从大到小获取有序集合中分数在指定区间内的成员,可选择是否返回成员的分数,还可通过limit指定返回结果的偏移量和数量 。
zcount key min maxO(log(n)),n是当前有序集合成员个数计算有序集合中分数在指定区间内的成员数量 。
zremrangebyrank key start endO(log(n)+k),k是要删除的成员个数,n是当前有序集合成员个数根据成员排名范围,从有序集合中删除指定区间内的成员 。
zremrangebyscore key min maxO(log(n)+k),k是要删除的成员个数,n是当前有序集合成员个数根据分数范围,从有序集合中删除分数在指定区间内的成员 。

有序集合的核心命令围绕元素分数(score)的增删查改、排序和集合运算展开,主要分为以下几类:

1. 元素操作
  • ZADD:添加或更新元素及其分数(支持 NX​、XX​、INCR​ 等选项)。

    ZADD leaderboard 100 "player1"  # 添加玩家1,分数100
    
  • ZREM:移除指定元素。

  • ZINCRBY:增减元素的分数(如积分变动)。

    ZINCRBY leaderboard 50 "player1"  # 玩家1分数+50
    
  • ZSCORE:获取元素分数。

2. 范围查询与排序
  • ZRANGE / ZREVRANGE:按分数升序/降序返回指定区间元素。
  • ZRANGEBYSCORE:按分数区间筛选元素(支持开闭区间)。
  • ZRANK / ZREVRANK:获取元素的正序/逆序排名。
3. 集合运算
  • ZINTERSTORE / ZUNIONSTORE:计算多个有序集合的交集/并集,结果存储到新键。

    ZINTERSTORE result 2 key1 key2  # 计算key1和key2的交集
    
4. 统计与删除
  • ZCARD:获取集合元素总数。
  • ZCOUNT:统计指定分数区间内的元素数量。
  • ZREMRANGEBYRANK / ZREMRANGEBYSCORE:按排名或分数区间批量删除元素。
5. 阻塞操作
  • BZPOPMAX / BZPOPMIN:阻塞弹出最高/最低分元素,适用于优先级队列。

二、内部编码

Redis 根据数据规模动态选择编码方式,以平衡内存和性能:

1. ziplist(压缩列表)
  • 触发条件

    • 元素数量 ≤ zset-max-ziplist-entries​(默认 128)。
    • 每个元素的成员(member)长度 ≤ zset-max-ziplist-value​(默认 64 字节)。
  • 特点

    • 内存紧凑,连续存储成员和分数,无指针开销。
    • 增删操作时间复杂度为 O(n),适用于小规模数据。
2. skiplist(跳表)
  • 触发条件:超出 ziplist 容量限制时自动转换。

  • 特点

    • 跳表+哈希表组合实现:跳表维护有序结构(O(logN) 查询),哈希表存储成员到分数的映射(O(1) 查询)。
    • 支持高效范围查询和动态数据插入。
3. 编码转换规则
  • 只允许从 ziplist 转为 skiplist,不可逆。
  • 可通过 OBJECT ENCODING key​ 查看当前编码类型。

三、使用场景

有序集合凭借唯一性有序性,适用于以下典型场景:

1. 排行榜系统
  • 代码案例: 音乐排行榜 统计音乐播放量以及相关排名信息

    package com.example.redis.sortedset;
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.Tuple;
    
    import java.util.Set;
    
    /**
     * 描述: 音乐排行榜系统
     * 使用 Redis 有序集合(Sorted Set)存储歌曲排行榜,key 为 RANKING_KEY(例如:"music:ranking")。
     * 每个元素的 score 用于表示歌播放量、点赞数等,可以根据具体业务情况计算。
     * 使用 zadd 命令添加或更新歌曲得分,zadd 如果已有成员会更新其得分,保证同一首歌曲不会重复添加。
     *  clickPlay 方法,每次点击播放时使用 jedis.zincrby(RANKING_KEY, 1, songId) 将歌曲的播放量加 1。
     * 使用 zrevrange 按分数降序查询排行榜,从而获取热门歌曲;同时可使用 zrevrank、zscore 获取歌曲排名和得分。
     * 示例中 main 函数模拟了添加/更新操作,并展示了如何获取排行榜、查询具体歌曲信息等操作
     * @author ZHOUXIAOYUE
     * @date 2025/4/21 15:19
     */
    public class MusicRankingSystem {
        // 定义排行榜对应的 Redis key
        private static final String RANKING_KEY = "music:ranking";
        private Jedis jedis;
        public MusicRankingSystem() {
            // 连接 Redis 服务,默认地址 localhost:6379
            jedis = new Jedis("localhost", 6379);
        }
        /**
         * 添加歌曲到排行榜
         * 如果歌曲已存在,则不会重复添加,初始播放量可为 0(或指定值)
         *
         * @param songId    歌曲 ID
         * @param playCount 初始播放量
         */
        public void addSong(String songId, double playCount) {
            // 判断歌曲是否已存在
            if (jedis.zscore(RANKING_KEY, songId) == null) {
                jedis.zadd(RANKING_KEY, playCount, songId);
                System.out.println("添加歌曲 " + songId + ",初始播放量为:" + playCount);
            } else {
                System.out.println("歌曲 " + songId + " 已存在,当前播放量为:" + jedis.zscore(RANKING_KEY, songId));
            }
        }
        /**
         * 模拟点击播放歌曲,每点击一次歌曲播放量自动+1
         *
         * @param songId 歌曲 ID
         */
        public void clickPlay(String songId) {
            // 使用 zincrby 实现播放量自动加 1
            double newPlayCount = jedis.zincrby(RANKING_KEY, 1, songId);
            System.out.println("歌曲 " + songId + " 播放一次,当前播放量为:" + newPlayCount);
        }
        /**
         * 获取排行榜前 N 名的歌曲(播放量从高到低排序)
         *
         * @param top 前 N 名
         * @return 歌曲 ID 集合
         */
        public Set<String> getTopSongs(int top) {
            // 使用 zrevrange 按播放量从高到低排序
            Set<String> topSongs = jedis.zrevrange(RANKING_KEY, 0, top - 1);
            System.out.println("排行榜前 " + top + " 名:" + topSongs);
            return topSongs;
        }
        /**
         * 获取某个歌曲的排名(排名从 1 开始,播放量越高排名越靠前)
         *
         * @param songId 歌曲 ID
         * @return 歌曲排名,歌曲不存在返回 -1
         */
        public long getSongRank(String songId) {
            Long rank = jedis.zrevrank(RANKING_KEY, songId);
            if (rank == null) {
                System.out.println("歌曲 " + songId + " 不在排行榜中。");
                return -1;
            } else {
                System.out.println("歌曲 " + songId + " 的排名是:" + (rank + 1));
                return rank + 1;
            }
        }
        /**
         * 获取某个歌曲的播放量
         *
         * @param songId 歌曲 ID
         * @return 播放量
         */
        public double getSongPlayCount(String songId) {
            Double playCount = jedis.zscore(RANKING_KEY, songId);
            System.out.println("歌曲 " + songId + " 的播放量为:" + playCount);
            return playCount == null ? 0 : playCount;
        }
        /**
         * 获取排行榜中指定区间的歌曲及播放量
         *
         * @param start 区间开始索引(从 0 开始)
         * @param end   区间结束索引
         */
        public void getSongsWithPlayCount(int start, int end) {
            Set<Tuple> tuples = jedis.zrevrangeWithScores(RANKING_KEY, start, end);
            System.out.println("排行榜区间 [" + start + ", " + end + "] 内的歌曲信息:");
            for (Tuple tuple : tuples) {
                System.out.println("歌曲 ID:" + tuple.getElement() + ",播放量:" + tuple.getScore());
            }
        }
        /**
         * 关闭 Jedis 连接
         */
        public void close() {
            if (jedis != null) {
                jedis.close();
            }
        }
        public static void main(String[] args) {
            MusicRankingSystem rankingSystem = new MusicRankingSystem();
            // 添加几首歌曲到排行榜,初始播放量设置为 0
            rankingSystem.addSong("song:101", 0);
            rankingSystem.addSong("song:102", 0);
            rankingSystem.addSong("song:103", 0);
            rankingSystem.addSong("song:104", 0);
            rankingSystem.addSong("song:105", 0);
            // 模拟点击播放,不同歌曲点击次数不同
            rankingSystem.clickPlay("song:101");
            rankingSystem.clickPlay("song:102");
            rankingSystem.clickPlay("song:101");
            rankingSystem.clickPlay("song:103");
            rankingSystem.clickPlay("song:102");
            rankingSystem.clickPlay("song:101");
            rankingSystem.clickPlay("song:104");
            rankingSystem.clickPlay("song:105");
            rankingSystem.clickPlay("song:103");
            rankingSystem.clickPlay("song:105");
            // 获取排行榜前 3 名的歌曲
            rankingSystem.getTopSongs(3);
            // 获取指定歌曲的排名与播放量
            rankingSystem.getSongRank("song:101");
            rankingSystem.getSongPlayCount("song:101");
            // 获取排行榜中索引 0~4 区间内的歌曲信息
            rankingSystem.getSongsWithPlayCount(0, 4);
            // 关闭连接
            rankingSystem.close();
        }
    }
    
  • 实现:以用户积分作为分数,利用 ZREVRANGE​ 获取排名前 N 的用户。

    ZREVRANGE leaderboard 0 9 WITHSCORES  # 获取Top10玩家及分数
    
2. 优先级队列
  • 实现:任务分数表示优先级,通过 BZPOPMAX​ 优先处理高优先级任务。
3. 时间轴/事件排序
  • 实现:以时间戳为分数,存储用户行为日志,按时间范围查询。

    ZADD user:1001:actions 1620000000 "login"
    ZRANGEBYSCORE user:1001:actions 1620000000 1620003600  # 查询某时间段行为
    
4. 动态统计与过滤
  • 实现:统计分数区间内元素(如商品价格区间)。

    ZCOUNT products 100 500  # 统计价格在100-500的商品数量
    
5. 数据去重与聚合
  • 实现:通过 ZINTERSTORE​ 计算用户兴趣标签的交集。

四、调优建议

  1. 内存优化

    • 小规模数据优先使用 ziplist,调整 zset-max-ziplist-entries​ 和 zset-max-ziplist-value​ 参数。
  2. 性能优化

    • 高频写入场景建议增大 ziplist 阈值,减少跳表转换开销。
  3. 查询优化

    • 避免全量遍历(如 ZRANGE 0 -1​),改用分页或迭代器(ZSCAN​)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2339937.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[c语言日寄]免费文档生成器——Doxygen在c语言程序中的使用

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…

QtCreator的设计器、预览功能能看到程序图标,编译运行后图标消失

重新更换虚拟机&#xff08;Vmware Kylin&#xff09;&#xff0c;重新编译和配置了很多第三方库后&#xff0c;将代码跑到新的这个虚拟机环境中&#xff0c;但是出现程序图标不可见&#xff0c;占位也消失&#xff0c;后来继续检查ui文件&#xff0c;ui文件图标也异常&#x…

面试常用基础算法

目录 快速排序归并排序堆排序 n n n皇后问题最大和子数组爬楼梯中心扩展法求最长回文子序列分割回文串动态规划求最长回文子序列最长回文子串单调栈双指针算法修改 分割回文串滑动窗口栈 快速排序 #include <iostream> #include <algorithm>using namespace std;…

悬空引用和之道、之禅-《分析模式》漫谈57

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 “Analysis Patterns”的第5章“对象引用”原文&#xff1a; Unless you can catch all such references, there is the risk of a dangling reference, which often has painful con…

【初阶数据结构】树——二叉树(上)

文章目录 目录 前言 一、树 1.树的概念与结构 2.树相关术语 3.树的表示 二、二叉树 1.概念与结构 2.特殊的二叉树 3.二叉树存储结构 总结 前言 本篇带大家学习一种非线性数据结构——树&#xff0c;简单认识树和二叉数以及了解二叉树的存储结构。 一、树 1.树的概念与结构 树…

ECharts散点图-散点图14,附视频讲解与代码下载

引言&#xff1a; ECharts散点图是一种常见的数据可视化图表类型&#xff0c;它通过在二维坐标系或其它坐标系中绘制散乱的点来展示数据之间的关系。本文将详细介绍如何使用ECharts库实现一个散点图&#xff0c;包括图表效果预览、视频讲解及代码下载&#xff0c;让你轻松掌握…

GAIA-2:用于自动驾驶的可控多视图生成世界模型

25年3月来自英国创业公司 Wayze 的论文“GAIA-2: A Controllable Multi-View Generative World Model for Autonomous Driving”。&#xff08;注&#xff1a;23年9月其发布GAIA-1&#xff09; 生成模型为模拟复杂环境提供一种可扩展且灵活的范例&#xff0c;但目前的方法不足…

浅谈AI致幻

文章目录 当前形势下存在的AI幻觉&#xff08;AI致幻&#xff09;什么是AI幻觉AI幻觉的类型为什么AI会产生幻觉AI幻觉的危害与影响当前应对AI幻觉的技术与方法行业与学术界的最新进展未来挑战与展望结论 当前形势下存在的AI幻觉&#xff08;AI致幻&#xff09; 什么是AI幻觉 …

车载软件架构 --- 二级boot设计说明需求规范

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…

Java高效合并Excel报表实战:GcExcel让数据处理更简单

前言&#xff1a;为什么需要自动化合并Excel&#xff1f; 在日常办公场景中&#xff0c;Excel报表合并是数据分析的基础操作。根据2023年企业办公效率报告显示&#xff1a; 财务人员平均每周花费6.2小时在Excel合并操作上人工合并的错误率高达15%90%的中大型企业已采用自动化…

第十四届蓝桥杯 2023 C/C++组 平方差

目录 题目&#xff1a; 题目描述&#xff1a; 题目链接&#xff1a; 思路&#xff1a; 核心思路&#xff1a; 第一种思路&#xff1a; 第二种思路&#xff1a; 坑点&#xff1a; 代码&#xff1a; 数学找规律 O(n) 50分代码详解&#xff1a; O(1)满分代码详解&#x…

I/O复用函数的使用——select

I/O复用函数的使用——select 目录 一、概念 二、select接口 2.1 基础概念 2.2 使用 select 函数的标准输入读取代码 2.3 基于 select 模型的多客户端 TCP 服务器实现 一、概念 i/o复用使得程序能同时监听多个文件描述符&#xff0c;可以提高程序性能。 之前为了让服务器能…

图像预处理-图像轮廓特征查找

其实就是外接轮廓&#xff0c;有了轮廓点就可以找到最上、最下、最左、最右的四个坐标&#xff08;因为有xmin,xmax,ymin,ymax&#xff09;。就可以绘制出矩形。 一.外接矩形 cv.boundingRect(轮廓点) - 返回x,y,w,h&#xff0c;传入一个轮廓的轮廓点&#xff0c;若有多个轮廓需…

全同态加密医疗数据分析集python实现

目录 摘要一、前言二、全同态加密与医疗数据分析概述2.1 全同态加密(FHE)简介2.2 医疗数据分析需求三、数据生成与预处理四、系统架构与流程4.1 系统架构图五、核心数学公式六、异步任务调度与(可选)GPU 加速七、PyQt6 GUI 设计八、完整代码实现九、自查测试与总结十、展望…

list的学习

list的介绍 list文档的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前一个元素和后一…

HarmonyOS:Navigation实现导航之页面设置和路由操作

导读 设置标题栏模式设置菜单栏设置工具栏路由操作页面跳转页面返回页面替换页面删除移动页面参数获取路由拦截 子页面页面显示类型页面生命周期页面监听和查询 页面转场关闭转场自定义转场共享元素转场 跨包动态路由系统路由表自定义路由表 示例代码 Navigation组件适用于模块…

管道位移自动化监测方案

一、背景 管道系统在区域性地质沉降作用下易形成非均匀应力场集中现象&#xff0c;诱发管体屈曲变形及环焊缝界面剥离等连续损伤累积效应&#xff0c;进而导致管道力学性能退化与临界承载能力衰减。传统人工巡检受限于空间覆盖度不足及数据采集周期长&#xff08;≥72h&#xf…

【学习笔记】机器学习(Machine Learning) | 第五周| 分类与逻辑回归

机器学习&#xff08;Machine Learning&#xff09; 简要声明 基于吴恩达教授(Andrew Ng)课程视频 BiliBili课程资源 文章目录 机器学习&#xff08;Machine Learning&#xff09;简要声明 一、逻辑回归的基本原理分类判断条件模型输出的解释Sigmoid 函数与 Logistic 函数逻辑…

Python 深度学习 第8章 计算机视觉中的深度学习 - 卷积神经网络使用实例

Python 深度学习 第8章 计算机视觉中的深度学习 - 卷积神经网络使用实例 内容概要 第8章深入探讨了计算机视觉中的深度学习&#xff0c;特别是卷积神经网络&#xff08;convnets&#xff09;的应用。本章详细介绍了卷积层和池化层的工作原理、数据增强技术、预训练模型的特征…

[免费]SpringBoot+Vue博物馆(预约)管理系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue博物馆(预约)管理系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue博物馆(预约)管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 随着计算机科学技术的日渐成熟&#xff…