当前位置: 首页 > news >正文

Redis值数据类型——sorted set

4.5 sorted set

4.5.1 概述

  1. 核心基础
有序集合(sorted set)是在普通集合(set)的基础上做了扩展,为集合中的每一个元素都关联了一个对应的分数(score)。
基于这个特性,它不仅支持普通集合的核心操作(插入、删除、判断元素是否存在),还额外支持一系列与分数相关的专属操作(如获取分数最高 / 最低的前 N 个元素、获取指定分数范围的元素等)。
  1. 与列表(list)类型的异同
(一)相同点(二者均具备有序性、范围查询能力)
二者存储的元素都是有序的;
二者都支持获取指定范围的元素。
(二)核心区别(底层实现与功能特性差异)
对比维度
列表(list)
有序集合(sorted set)
底层实现
双向链表
散列表
访问性能
靠近两端的数据访问速度极快,元素增多后,访问中间数据速度变慢
无论首尾还是中间数据,访问速度都很快(高效)
元素位置调整
无法简单调整单个元素的位置
可通过
修改元素关联的分数
,灵活调整元素位置
内存消耗
内存占用相对较低
内存消耗更高(因需额外存储分数及维护有序结构)
  1. 总结
  • sorted set 基于普通 set 扩展,核心特性是「元素唯一 + 关联分数 + 有序排列」;
  • 与 list 同为有序且支持范围查询,但底层实现、访问性能、功能灵活性、内存消耗均有显著差异;
  • sorted set 更适合需要基于分数排序、高效查询中间数据的场景,代价是更高的内存占用。

4.5.2 命令

  1. 增加元素
向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会用新的分数替换原有的分数。返回值是新加入到集合中的元素个数,不包含之前已经存在的元素。
ZADD key score member [score member ...]

2.获取元素的分数

ZSCORE key member

  1. 获取排名在某个范围的元素列表
  • 按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素(包含两端的元素)。
ZRANGE key start stop [WITHSCORES]
先将该有序集合的所有元素,按照分数(score)从小到大(升序)进行排序,形成一个有序的 “虚拟列表”;
这个排序后的 “虚拟列表”下标从 0 开始(和 Redis List、Java 数组下标规则一致);
按照 start 和 stop 指定的下标范围,返回该范围内的所有元素(包含 start 和 stop 对应的元素);
可选参数 WITHSCORES:加上该参数后,返回结果会同时携带元素的值(member)和对应的分数(score),不加则只返回元素值。
  • 照元素分数从大到小的顺序返回索引从start到stop之间的所有元素(包含两端的元素)
ZREVRANGE key start stop [WITHSCORES]

  1. 获得指定分数范围的元素
ZRANGEBYSCORE key min max [WITHSCORES][LIMIT offset count]

(min / (max:给 min 或 max 加上括号,代表不包含该边界值(默认是包含边界值的)。
offset:是在符合分数范围的结果列表里的起始下标(从 0 开始)。
  1. 增加某个元素的分数
返回值是更改后的分数
ZINCRBY key increment member

6.获得集合中元素的数量

ZCARD key

7.获得指定分数范围内的元素个数

ZCOUNT key min max

8.按照排名范围删除元素

按分数从小到大(升序)排序

ZREMRANGEBYRANK key start stop

  1. 按照分数范围删除元素
ZREMRANGEBYSCORE key min max

10.获取元素的排名

#从小到大 ZRANK key member #从大到小 ZREVRANK key member

4.5.3 方法

  1. sorted set类型核心操作
Redis 命令
StringRedisTemplate 核心方法
功能说明
zadd
opsForZSet().add(key, member, score)
添加 / 更新有序集合元素
zscore
opsForZSet().score(key, member)
获取元素对应的分数
zrange
opsForZSet().range(key, start, stop)
升序获取指定排名范围元素
zrange withscores
opsForZSet().rangeWithScores(key, start, stop)
升序获取元素并携带分数
zrevrange
opsForZSet().reverseRange(key, start, stop)
降序获取指定排名范围元素
zrangebyscore
opsForZSet().rangeByScore(key, min, max)
按分数范围获取元素
zrangebyscore withscores
opsForZSet().rangeByScoreWithScores(key, min, max)
按分数范围获取元素并携带分数
zincrby
opsForZSet().incrementScore(key, member, increment)
给元素增加指定分数
zcard
opsForZSet().size(key)
获取有序集合元素总数
zcount
opsForZSet().count(key, min, max)
获取指定分数范围的元素个数
zrem
opsForZSet().remove(key, member)
删除有序集合中的指定元素
zremrangebyrank
opsForZSet().removeRange(key, start, stop)
按排名范围删除元素
zremrangebyscore
opsForZSet().removeRangeByScore(key, min, max)
按分数范围删除元素
zrank
opsForZSet().rank(key, member)
升序获取元素的排名(从 0 开始)
zrevrank
opsForZSet().reverseRank(key, member)
降序获取元素的排名(从 0 开始)
  1. 总结
SpringBoot 中操作 Redis Sorted Set 的核心套路是 stringRedisTemplate.opsForZSet().xxx()。
  1. 代码

package com.qcby.springbootredis; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ZSetOperations; import java.util.Set; import java.util.stream.Collectors; @SpringBootTest public class SortedSetTest { @Autowired private StringRedisTemplate stringRedisTemplate; @Test public void testSortedSetCoreCommands() { String scoreboardKey = "scoreboard"; String hackersKey = "hackers"; String zsetKey = "zset"; try { // 10.2.1 增加元素(ZADD)+ 获取元素分数(ZSCORE) Boolean add1 = stringRedisTemplate.opsForZSet().add(scoreboardKey, "zhangsan", 80); stringRedisTemplate.opsForZSet().add(scoreboardKey, "lisi", 89); stringRedisTemplate.opsForZSet().add(scoreboardKey, "wangwu", 94); System.out.println("新增 zhangsan:" + add1); Boolean add2 = stringRedisTemplate.opsForZSet().add(scoreboardKey, "lisi", 97); System.out.println("更新 lisi 分数:" + add2); Double lisiScore = stringRedisTemplate.opsForZSet().score(scoreboardKey, "lisi"); System.out.println("lisi 的分数:" + lisiScore); // 10.2.2 获得排名范围的元素列表(ZRANGE / ZREVRANGE) Set<String> zrangeResult = stringRedisTemplate.opsForZSet().range(scoreboardKey, 0, 2); System.out.println("升序排名 0-2 元素:" + zrangeResult); Set<ZSetOperations.TypedTuple<String>> zrangeWithScores = stringRedisTemplate.opsForZSet().rangeWithScores(scoreboardKey, 0, 1); Set<String> withScoresStr = zrangeWithScores.stream() .map(t -> t.getValue() + "(" + t.getScore() + ")") .collect(Collectors.toSet()); System.out.println("升序带分数:" + withScoresStr); Set<String> zrevrangeResult = stringRedisTemplate.opsForZSet().reverseRange(scoreboardKey, 0, 2); System.out.println("降序排名 0-2 元素:" + zrevrangeResult); // 10.2.3 获得指定分数范围的元素(ZRANGEBYSCORE) Set<ZSetOperations.TypedTuple<String>> zrangeByScore1 = stringRedisTemplate.opsForZSet().rangeByScoreWithScores(scoreboardKey, 90, 97); Set<String> scoreWithStr1 = zrangeByScore1.stream() .map(t -> t.getValue() + "(" + t.getScore() + ")") .collect(Collectors.toSet()); System.out.println("分数 90-97 带分数:" + scoreWithStr1); // 半开区间 90 <= score < 97 Set<ZSetOperations.TypedTuple<String>> zrangeByScore2 = stringRedisTemplate.opsForZSet().rangeByScoreWithScores(scoreboardKey, 90, 96.999); Set<String> scoreWithStr2 = zrangeByScore2.stream() .map(t -> t.getValue() + "(" + t.getScore() + ")") .collect(Collectors.toSet()); System.out.println("分数 90-(97) 带分数:" + scoreWithStr2); // 分页 LIMIT 1 2 Set<String> zrangeByScore3 = stringRedisTemplate.opsForZSet().rangeByScore(scoreboardKey, 70, 100, 1, 2); System.out.println("分数 70-100 分页:" + zrangeByScore3); // 10.2.4 增加元素分数(ZINCRBY)+ 集合元素数量(ZCARD)+ 分数范围元素个数(ZCOUNT) Double newLisiScore = stringRedisTemplate.opsForZSet().incrementScore(scoreboardKey, "lisi", 4); System.out.println("lisi 加4分后:" + newLisiScore); Long zcardCount = stringRedisTemplate.opsForZSet().size(scoreboardKey); System.out.println("集合元素个数:" + zcardCount); Long zcount = stringRedisTemplate.opsForZSet().count(scoreboardKey, 80, 90); System.out.println("分数 80-90 元素个数:" + zcount); stringRedisTemplate.opsForZSet().add(hackersKey, "Alan Kay", 1940); stringRedisTemplate.opsForZSet().add(hackersKey, "Richard Stallman", 1953); stringRedisTemplate.opsForZSet().add(hackersKey, "Yukihiro Matsumoto", 1965); stringRedisTemplate.opsForZSet().add(hackersKey, "Claude Shannon", 1916); stringRedisTemplate.opsForZSet().add(hackersKey, "Linus Torvalds", 1969); stringRedisTemplate.opsForZSet().add(hackersKey, "Alan Turing", 1912); Set<String> hackersZrange = stringRedisTemplate.opsForZSet().range(hackersKey, 0, -1); System.out.println("hackers 升序:" + hackersZrange); Set<String> hackersZrevrange = stringRedisTemplate.opsForZSet().reverseRange(hackersKey, 0, -1); System.out.println("hackers 降序:" + hackersZrevrange); // 清空当前数据库 stringRedisTemplate.getConnectionFactory().getConnection().flushDb(); System.out.println("清空数据库成功"); // zset 示例 stringRedisTemplate.opsForZSet().add(zsetKey, "hello", 10.1); stringRedisTemplate.opsForZSet().add(zsetKey, ":", 10.0); stringRedisTemplate.opsForZSet().add(zsetKey, "zset", 9.0); stringRedisTemplate.opsForZSet().add(zsetKey, "zset!", 11.0); Long zsetCard = stringRedisTemplate.opsForZSet().size(zsetKey); System.out.println("zset 元素个数:" + zsetCard); Double zsetScore = stringRedisTemplate.opsForZSet().score(zsetKey, "zset"); System.out.println("zset 的分数:" + zsetScore); Set<String> zsetZrange = stringRedisTemplate.opsForZSet().range(zsetKey, 0, -1); System.out.println("zset 升序:" + zsetZrange); Long zremCount = stringRedisTemplate.opsForZSet().remove(zsetKey, "zset!"); System.out.println("删除 zset!:" + zremCount); Long zsetZcount = stringRedisTemplate.opsForZSet().count(zsetKey, 9.5, 10.5); System.out.println("分数 9.5-10.5 元素个数:" + zsetZcount); Set<String> zsetFinal = stringRedisTemplate.opsForZSet().range(zsetKey, 0, -1); System.out.println("zset 删除后:" + zsetFinal); // 10.2.5 其他命令(ZREMRANGEBYRANK / ZREMRANGEBYSCORE / ZRANK / ZREVRANK) stringRedisTemplate.opsForZSet().add(scoreboardKey, "zhangsan", 80); stringRedisTemplate.opsForZSet().add(scoreboardKey, "lisi", 97); stringRedisTemplate.opsForZSet().add(scoreboardKey, "wangwu", 94); Long zremByRankCount = stringRedisTemplate.opsForZSet().removeRange(scoreboardKey, 0, 1); System.out.println("按排名删除 0-1:" + zremByRankCount); Set<String> scoreboardAfterRankDel = stringRedisTemplate.opsForZSet().range(scoreboardKey, 0, -1); System.out.println("删除后元素:" + scoreboardAfterRankDel); stringRedisTemplate.opsForZSet().add(scoreboardKey, "zhangsan", 84); Long zremByScoreCount = stringRedisTemplate.opsForZSet().removeRangeByScore(scoreboardKey, 80, 100); System.out.println("按分数删除 80-100:" + zremByScoreCount); stringRedisTemplate.opsForZSet().add(scoreboardKey, "zhangsan", 80); stringRedisTemplate.opsForZSet().add(scoreboardKey, "lisi", 97); Long lisiRank = stringRedisTemplate.opsForZSet().rank(scoreboardKey, "lisi"); System.out.println("lisi 升序排名:" + lisiRank); Long zhangsanRevRank = stringRedisTemplate.opsForZSet().reverseRank(scoreboardKey, "zhangsan"); System.out.println("zhangsan 降序排名:" + zhangsanRevRank); } catch (Exception e) { e.printStackTrace(); } } }
http://www.cnnetsun.cn/news/1344288.html

相关文章:

  • 双令牌机制:让认证更安全、体验更流畅
  • 互联网大厂Java面试实战:以智慧物流场景为例深入探讨Spring Boot、微服务与Redis缓存
  • Metasploitable靶机的下载与安装
  • Claude国内镜像站实测:可扩展监督与宪法AI,推理架构的范式革命
  • OpenClaw 高效配置与集成指南:从模型选择到 API 对接
  • 游戏盾终极奥义:湘情盾“源站隐身”与“报文基因”实战解析
  • Claude Code超详细完整指南附最佳实践(最新版2026年,可接入GLM)
  • 3.17打卡day31
  • KIHU快狐|带API协议户外液晶显示器支持第三方平台对接
  • 测试学习Day6——Linux和数据库(1)
  • 2026年DeepSeek写的论文AI率太高?3款降AI工具实测推荐
  • Gradle框架:现代软件构建的灵活引擎
  • 二氢视黄醛价格
  • 解决AI模型版本同步问题:架构师的3套方案
  • 大模型如何赋能RAG?深度解析大模型原理与选择策略!
  • 基于SwanLinkOS/OpenHarmony操作系统设计的智慧工厂项目(二)项目环境的搭建
  • AI赋能嵌入式研发:效率革命与智能升级
  • 2026年制作文旅宣传图,搜索关键词比找对网站更关键
  • 欧意下载okxz.run复制打开 下载教程2026最新
  • QT信号与槽机制全解析
  • 使用Jsoup爬取豆瓣电影Top250(附Java代码)
  • 在WebFuture里如何自动处理二维码问题脚本
  • 11-AI基础概念入门
  • django flask+uniapp 酒店管理系统设计 小程序_54ybz
  • 如何解决嵌套在公众号里面的H5页面有缓存的问题。公众号菜单的H5的域名不希望加版本号去修改
  • DataTable学习路线
  • 芯片解密多少钱,单片机解密价格详细解析
  • 2026必备!全行业通用降AI率平台 千笔·降AIGC助手 VS 万方智搜AI
  • 【用 Java API Client 操作 Elasticsearch】
  • AI智能体中的Skills是什么?