ZSet 的 score 只能是浮点数需将多维权重压缩为单个数值按量级错位相加如 quality×10? (ts%10?)×100 hot用 Lua 脚本统一计算防精度差异避免 ZINCRBY 局部更新并控制总分在 1e14 内防精度丢失。ZSet 的 score 只能存一个数字怎么塞进多个权重直接往 ZSet 的 score 里硬塞多个维度比如热度时间质量不行——Redis 不支持复合 score它只认浮点数。常见错误是试图用 JSON 字符串当 scoreZADD myzset {hot:10,time:1698765432} item1结果 Redis 报错 ERR value is not a valid float。真正可行的做法是把多维数据「压缩」成单个浮点数。核心思路给每个维度分配权重区间错位相加避免干扰。比如热度0–1000占低 6 位hot * 1时间戳秒级如 1717023456取后 6 位避免过大再左移 6 位(ts % 1000000) * 100质量分0–10左移 12 位quality * 1000000最终 score quality * 1000000 (ts % 1000000) * 100 hot这样 quality 改动 1就比时间戳变动整整 100 秒还影响大时间戳变化 1 秒也远超热度变化 100 点。顺序和量级必须手动对齐否则排序会乱。用 Lua 脚本动态算分避免客户端反复解析如果每次插入都靠应用层算 score容易在不同语言/版本间出现浮点精度不一致比如 Python 的 round() 和 Java 的 Math.round() 对负数处理不同导致同一组输入算出不同 scoreZSet 排序错乱。更稳的方式是把计算逻辑下沉到 Redis 服务端用 EVAL 执行 LuaEVAL return ARGV[1]*1000000 (ARGV[2]%1000000)*100 ARGV[3] 0 3 1717023456 95注意三点ARGV 是字符串数组Lua 里要显式转成 numbertonumber(ARGV[1])不要在 Lua 里做耗时操作如遍历大集合否则阻塞 Redis 主线程脚本里不能调用 redis.call(TIME) 这类命令来实时取时间——ZSet 需要确定性 score时间必须由客户端传入分数溢出和精度丢失的真实风险Redis 的 score 内部用 double 存储有效精度约 15 位十进制数字。一旦你把三个维度全拉到高位比如质量 × 1e12 时间 × 1e6 热度总和超过 90071992547409922^53就会开始丢精度——两个本该不同的 score 可能被存成同一个值排序失效。 标贝科技 标贝科技-专业AI语音服务的人工智能开放平台