Redis命令:HRANDFIELD

Redis HRANDFIELD 命令详细教程

HRANDFIELD 从 Hash 中随机返回一个或多个字段,可选同时返回值。它从 Redis 6.2.0 起提供,正数与负数 count 的行为完全不同。

资料合集:https://pan.quark.cn/s/10e98d308913、https://pan.quark.cn/s/f56bc69c5338

一、概览与语法

redis 复制代码
HRANDFIELD key [count [WITHVALUES]]
项目 说明
数据类型 Hash
支持版本 Redis 6.2.0 起
key 一个 Hash Key
count 可选,返回字段的数量;正负号决定是否允许重复
WITHVALUES 可选,同时返回值;只能与 count 一起使用
时间复杂度 O(N),N 为返回的字段数量
ACL @read、@hash、@slow
命令标记 readonly

不传 count 时返回单个随机字段(字符串或空值);传入 count 时返回数组;同时传入 count 与 WITHVALUES 时返回字段与值交替的数组。$TRAE_REF

二、正数 count 与负数 count 的区别

这是本命令最重要的行为分界,官方对此有明确说明:

对比项 count 为正数 count 为负数
是否可能重复 不重复,返回不同的字段 允许同一字段多次出现
返回数量 min(count, 字段总数) 恰好为 abs(count)
Key 不存在时 空数组 空数组
顺序 并非真正随机,需要客户端自行打乱 真正随机

官方原文指出:当 count 为正时,不会返回重复字段;若 count 大于 Hash 的字段数量,只返回整个 Hash,不会补充额外字段;且回复中字段的顺序并非真正随机,客户端如需随机顺序应自行洗牌。当 count 为负时,可能返回重复字段,始终返回恰好 |count| 个字段(Hash 为空时返回空数组),且顺序是真正随机的。$TRAE_REF

三、基础示例

以下命令需要 Redis 6.2 或更新版本,在测试实例的 redis-cli 中执行。文中结果是预期说明,未实际连接 Redis 运行。示例沿用官方示例的数据。

redis 复制代码
DEL tutorial:{hrandfield}:coin
HSET tutorial:{hrandfield}:coin heads obverse tails reverse edge null
HLEN tutorial:{hrandfield}:coin
HRANDFIELD tutorial:{hrandfield}:coin
HRANDFIELD tutorial:{hrandfield}:coin 2
HRANDFIELD tutorial:{hrandfield}:coin 10
HRANDFIELD tutorial:{hrandfield}:coin -5
HRANDFIELD tutorial:{hrandfield}:coin -5 WITHVALUES

预期结果:HSET 返回 3,HLEN 返回 3。不带 count 时返回三个字段名之一。count 2 返回 2 个不重复的字段名。count 10 大于字段总数 3,只返回全部 3 个字段,不补充重复项。count -5 返回恰好 5 个字段名,其中可能有重复。带 WITHVALUES 时返回 10 个元素(字段与值交替)。

四、返回值形态汇总

调用形式 Key 存在 Key 不存在
HRANDFIELD key 单个字段名(字符串) 空值(Nil / Null)
HRANDFIELD key count(正) 字段名数组,长度 ≤ 字段总数 空数组
HRANDFIELD key count(负) 字段名数组,长度 = abs(count) 空数组
HRANDFIELD key count WITHVALUES 字段与值交替数组,长度 = 2 × 字段数 空数组

RESP2 与 RESP3 的差异只体现在"空值"的表示上:RESP2 为空批量字符串,RESP3 为 Null。数组形态两者一致。

注意不带 count 时返回的是字符串而非数组,与带 count 时的返回类型不同,客户端处理时需要区分,不能统一按数组处理。

五、WITHVALUES 的使用限制

WITHVALUES 只能与 count 一起使用。HRANDFIELD key WITHVALUES 会报语法错误,因为缺少 count。这一点与 SRANDMEMBER 不同(后者不支持返回值),也不要把 WITHVALUES 与 HRANDFIELD 单独使用时混淆。

redis 复制代码
HRANDFIELD tutorial:{hrandfield}:coin WITHVALUES

上述命令会报错。正确写法是 HRANDFIELD tutorial:{hrandfield}:coin 2 WITHVALUES。

带 WITHVALUES 的返回是扁平数组,需要成对解析:

python 复制代码
pairs = ["heads", "obverse", "tails", "reverse"]
result = {pairs[i]: pairs[i + 1] for i in range(0, len(pairs), 2)}
print(result)   # {'heads': 'obverse', 'tails': 'reverse'}

六、边界情况与错误处理

场景 行为
Key 不存在 不带 count 返回空值;带 count 返回空数组
count 为 0 返回空数组
count 为正且超过字段总数 只返回全部字段,不重复
count 为负 返回恰好 abs(count) 个,可能重复
count 不是整数 报参数类型错误
Key 是 String、List 等非 Hash 报 WRONGTYPE 错误
WITHVALUES 单独使用 报语法错误

由于 Redis 中不存在零字段的 Hash,返回空数组只有一种解释:Key 不存在或已到期。

七、客户端示例

前提为已安装 redis-py 并准备好本地测试实例。

python 复制代码
import random
import redis

r = redis.Redis(host="localhost", port=6379, decode_responses=True)
k = "tutorial:{hrandfield}:python"
try:
    r.delete(k)
    r.hset(k, mapping={"a": "1", "b": "2", "c": "3"})

    print(r.hrandfield(k))              # 单个字段名,如 'b'
    print(r.hrandfield(k, 2))           # 2 个不重复字段
    print(r.hrandfield(k, 10))          # 最多 3 个,不会重复
    print(r.hrandfield(k, -5))          # 恰好 5 个,可能重复
    print(r.hrandfield(k, 2, withvalues=True))   # ['a', '1', 'c', '3'] 形式

    # 需要真正随机的顺序时,客户端自行洗牌
    fields = r.hrandfield(k, 3)
    random.shuffle(fields)
    print(fields)

    print(r.hrandfield("tutorial:{hrandfield}:missing"))   # None
    print(r.hrandfield("tutorial:{hrandfield}:missing", 3))  # []
finally:
    r.delete(k)
    r.close()

Java(Jedis)示例:

java 复制代码
try (Jedis jedis = new Jedis("localhost", 6379)) {
    jedis.hset("tutorial:{hrandfield}:java", "a", "1");
    jedis.hset("tutorial:{hrandfield}:java", "b", "2");
    System.out.println(jedis.hrandfield("tutorial:{hrandfield}:java"));      // 单个字段
    System.out.println(jedis.hrandfield("tutorial:{hrandfield}:java", 2));   // List
    jedis.del("tutorial:{hrandfield}:java");
}

八、典型场景与性能建议

典型用途:从候选集中随机抽样(抽奖、A/B 实验分流、随机推荐)、负载均衡式挑选一个分片、从大 Hash 中随机预览若干字段以了解结构、按权重从多个配置中随机选一。

性能上,复杂度为 O(N) 且 N 是返回的字段数量,因此返回少量字段时开销很小;但 count 很大时会一次性传输大量数据。该命令被标记为 @slow,在大 Hash 上取大量样本时应评估影响。随机抽样不是无偏的加权抽样:每个字段被选中的概率相同,若需要按权重抽样,应在应用层实现。

九、练习、排错与总结

练习:新建 tutorial:{hrandfield}:exercise,写入 a、b、c 三个字段;连续执行多次 HRANDFIELD ... 1 观察结果变化;执行 HRANDFIELD ... 10 确认最多返回 3 个且不重复;执行 HRANDFIELD ... -10 确认恰好返回 10 个且可能出现重复;执行 HRANDFIELD ... 2 WITHVALUES 确认返回 4 个元素。

排错要点:不带 count 返回字符串、带 count 返回数组,客户端处理需区分;返回空数组说明 Key 不存在;WITHVALUES 报错说明缺少 count;unknown command 时确认服务端版本不低于 6.2;结果顺序不符合预期时注意正数 count 的顺序并非真正随机,应自行洗牌;报 WRONGTYPE 时用 TYPE 检查类型。清理使用 DEL tutorial:{hrandfield}:coin tutorial:{hrandfield}:exercise。速记:6.2 起支持、正数 count 不重复且数量受限、负数 count 允许重复且数量精确、WITHVALUES 必须搭配 count、顺序不保证。

相关推荐
jyOverQ1 小时前
Redis 持久化怎么做?RDB、AOF 与混合持久化
数据库·redis
于指尖飞舞1 小时前
mysql和redis面试题总结
数据库·redis·mysql
要开心吖ZSH2 小时前
系统并发与 QPS 上限:从 200 个线程到每秒几万请求
redis·mysql·tomcat·并发·连接池·qps
sinat_286945192 小时前
大模型推理:部署方式与性能优化思路
人工智能·算法·缓存·chatgpt·性能优化
ly768917 小时前
Redis 大 Key 与热点 Key 生产治理:发现、拆分、限流与本地缓存的组合策略
redis·限流·本地缓存·大key·热点key
青茶36019 小时前
开发一个网站插件,什么时候用到缓存存储功能呢?
缓存·网站
海绵宝宝转agent19 小时前
Pico 学习笔记 Harness 设计、历史压缩、三类目录与缓存复用
笔记·学习·缓存
ShineWinsu20 小时前
对于Redis:AOF持久化的解析
linux·数据库·redis·缓存·面试·持久化·aof