Lecture05-Redis-数据类型-ZSet与高级类型

文章目录

    [toc]

    单词词性音标含义
    rankn./v./ræŋk/排名(ZRANK 升序排名、ZREVRANK 降序排名)
    scoren./skɔː(r)/分数(ZSet 每个成员的权重,按它排序)
    sortedadj./ˈsɔːtɪd/有序的(ZSet 元素按 score 从小到大排序)
    geospatialadj./ˌdʒiːəʊˈspeɪʃl/地理空间的(Geo 类型存经纬度,按半径查附近)
    hyperloglogn./ˌhaɪpəˈlɒɡlɒɡlɒɡ/基数统计(PFADD/PFCOUNT 估算不重复元素个数,内存极小)
    bitmapn./ˈbɪtmæp/位图(SETBIT/GETBIT/BITCOUNT 对二进制位操作,签到用)
    cardinalityn./ˌkɑːdɪˈnæləti/基数(集合中不重复元素的个数)
    streamn./striːm/流(Redis 5+ 的日志型消息队列,生产者/消费者组)

    Lecture05-Redis-数据类型-ZSet与高级类型

    1、ZSet(有序集合)

    1、什么是 ZSet

    ZSet 和 Set 一样是去重的成员集合,但每个成员关联一个 score(分数,double),成员按 score 从小到大排序。

    Key = "rank:game"
      member(玩家)     score(分数)
      ┌─────────────┐
      │  jerry      87     ← 排名 0(最低)
      │  harry     136
      │  peter     155     ← 排名 2(最高)
      └─────────────┘
    
    • 成员唯一,score 可以重复。
    • 底层:小数据用 ziplist,大数据用 跳表 skiplist + dict(查找快 + 范围查询 + 唯一性检查兼顾)。

    2、常用命令

    命令功能
    zadd key score member [score member...]添加成员及分数
    zrange key 起始 结束 [WITHSCORES]升序返回索引区间(0 第一个,-1 最后一个)
    zrevrange key 起始 结束 [WITHSCORES]降序返回(排行榜第一名在前)
    zrangebyscore key min max [WITHSCORES]按分数区间升序返回
    zrevrangebyscore key max min [WITHSCORES]按分数区间降序返回
    zincrby key 增量 member给成员 score 加增量(排行榜实时加分)
    zrem key member删除成员
    zcount key min max统计分数区间内成员个数
    zrank key member升序排名(从 0 开始)
    zrevrank key member降序排名
    zscore key member取成员分数
    zpopmax/zpopmin key [n]弹出分数最高/最低的 n 个(延迟任务取最紧急)

    3、操作演示

    # 添加 5 名玩家成绩
    127.0.0.1:6379> zadd rank:game 55.5 gang 65.5 ming 75.5 qiang 85.5 jun 95.5 hong
    (integer) 5
    
    # 升序(分数从小到大)
    127.0.0.1:6379> zrange rank:game 0 -1 withscores
     1) "gang"
     2) "55.5"
     ...
    # 降序(排行榜第一名在前)
    127.0.0.1:6379> zrevrange rank:game 0 -1 withscores
     1) "hong"
     2) "95.5"
     ...
    
    # 分数区间查询:60~90 分的学生
    127.0.0.1:6379> zrangebyscore rank:game 60 90 withscores
    1) "ming"
    2) "65.5"
    ...
    
    # 实时加分
    127.0.0.1:6379> zincrby rank:game 5 gang
    "60.5"
    
    # 排名
    127.0.0.1:6379> zrank rank:game ming
    (integer) 0
    127.0.0.1:6379> zrevrank rank:game hong
    (integer) 0
    

    4、典型应用场景

    场景用法
    排行榜分数做 score,ZREVRANGE 0 -1 取前 N 名
    延迟任务 / 定时队列到期时间戳做 score,ZRANGEBYSCORE now +inf 取到期任务,ZPOPMIN 取最紧急
    购物车 / 最新订单时间戳做 score,按时间排序取列表
    打赏 / 人气榜ZINCRBY 实时累加分数
    限流 / 滑动窗口时间戳做 member,ZREMRANGEBYSCORE 清理窗口外数据

    2、Geo(地理位置,了解)

    Redis 3.2+ 提供,底层用 ZSet 实现(score 存经纬度编码),用于"附近的人/门店"。

    命令功能
    geoadd key 经度 纬度 成员添加位置
    geopos key 成员获取成员经纬度
    geodist key a b [km]计算两地直线距离
    georadius key 经 纬 半径 km以给定坐标为中心,半径内查成员
    georadiusbymember key 成员 半径 km以某个成员为中心,半径内查其他成员
    127.0.0.1:6379> geoadd city:pos 114.085947 22.547 shenzhen
    (integer) 1
    127.0.0.1:6379> geoadd city:pos 113.280637 23.125178 guangzhou
    (integer) 1
    127.0.0.1:6379> geodist city:pos shenzhen guangzhou km
    "104.6426"
    127.0.0.1:6379> georadius city:pos 114 22 100 km
    1) "shenzhen"
    

    经纬度可通过 http://www.jsons.cn/lngcode 这类网站查询。注意有效经度 -180~180、纬度 -85.05~85.05。


    3、HyperLogLog(基数统计)

    用于大数据量去重计数(如统计 UV:一个用户一天访问多次只算一次)。每个键约 12KB 内存,可估算近 2^64 个不同元素。

    命令功能
    pfadd key 元素...添加元素(去重)
    pfcount key [key...]统计不重复元素个数
    pfmerge dest s1 s2合并多个统计到 dest
    127.0.0.1:6379> pfadd uv:2026-09-28 userA userB userC userA userB
    (integer) 1
    127.0.0.1:6379> pfcount uv:2026-09-28
    (integer) 3          # 重复的 userA/userB 只算一次
    

    特点:省内存、快、结果有极小误差(约 0.81%)。适合"只要数量级、不要精确"的场景,如 UV、独立访客数。


    4、Bitmap(位图)

    对 String 的二进制位操作,每个位 0/1。适合大量布尔标记(签到、在线状态),极致省内存(1 亿用户每天 1 位 ≈ 12MB)。

    命令功能
    setbit key 位 0/1设置某一位
    getbit key 位读取某一位
    bitcount key统计所有为 1 的位数量
    # 签到:位 0 表示第 1 天
    127.0.0.1:6379> setbit sign:user:1001 0 1
    (integer) 0
    127.0.0.1:6379> setbit sign:user:1001 1 1
    (integer) 0
    127.0.0.1:6379> getbit sign:user:1001 1
    (integer) 1
    127.0.0.1:6379> bitcount sign:user:1001
    (integer) 2          # 连续签到 2 天
    

    经典用法:连续签到天数、在线状态、布隆过滤器(与 L7 缓存穿透有关)。


    5、Stream(流式消息队列,了解)

    Redis 5+ 提供日志型消息队列,支持多消费者、消费者组、消息确认,比 List 队列功能更完整,可作为轻量消息中间件(正式消息中间件见后续 RabbitMQ 课程)。

    # 生产者
    127.0.0.1:6379> xadd order:stream * order_id 1001 amount 99
    "1727400000000-0"
    
    # 消费者组读取(略)
    

    本课程只做了解:真正做消息队列,项目里更多用 RabbitMQ / Kafka。Redis Stream 适合"顺便用一下、不想引入额外中间件"的简单场景。


    6、数据类型总结

    类型特点典型场景
    string二进制安全、原子计数验证码、Token、计数器
    hash对象字段级读写用户信息、购物车
    list有序可重复,头尾快队列、栈、最新列表
    set去重、集合运算关注、去重、抽奖、标签
    zset有序去重,按分数排排行榜、延迟任务
    geo经纬度、半径查询附近的人/门店
    hyperloglog基数统计、省内存UV、独立访客
    bitmap位操作、极省内存签到、在线状态、布隆
    stream日志型消息队列简单异步消息、日志

    7、课堂练习

    1. 用 ZSet 做一个"本周热销榜":ZADD 5 个商品及销量,用 ZREVRANGE 0 2 取前三名,再用 ZINCRBY 给一个商品加分看排名变化。
    2. 用 HyperLogLog 统计"今日 UV":PFADD 若干用户(含重复),PFCOUNT 看结果。
    3. 用 Bitmap 做"连续签到 7 天":SETBIT 前 7 位为 1,BITCOUNT 得到 7。
    4. (了解)用 GEOADD/GEODIST 记录两个城市并计算距离。

    8、本节验证

    • 会用 ZADD/ZRANGE/ZREVRANGE/ZRANK/ZSCORE 实现排行榜与按分数查询 ✅
    • 会用 ZINCRBY 实时加分、按分数区间查询 ✅
    • 了解 Geo 附近查询、HyperLogLog 基数统计、Bitmap 位图签到 ✅
    • 了解 Stream 流式消息队列,能根据场景选对数据类型 ✅
    end