Redis命令:LPOS

Redis LPOS 命令详细教程

LPOS 用于在列表中查找与给定值匹配的元素,并返回其索引位置。它支持从表头或表尾开始查找、指定从第几个匹配开始、一次返回多个匹配位置,以及限制比较的元素数量,是"按值定位"列表元素的只读命令。它从 Redis 6.0.6 起提供,在此之前只能用 LRANGE 自己遍历实现。

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

一、概览与语法

redis 复制代码
LPOS key element [RANK rank] [COUNT num-matches] [MAXLEN len]
项目 说明
数据类型 List
支持版本 Redis 6.0.6 起
key 目标列表 Key
element 要查找的元素,按字节精确匹配,允许空字符串
RANK rank 从第几个匹配开始返回;1 表示第一个匹配,负数表示从表尾倒数(-1 为最后一个匹配)
COUNT num-matches 一次返回多个匹配位置;0 表示返回全部匹配
MAXLEN len 最多比较的元素数量;0 表示不限制
返回值 单结果模式返回匹配元素的 0 基索引,无匹配返回空值;带 COUNT 时返回索引数组,无匹配返回空数组
时间复杂度 O(N),N 为需要比较的元素数(受 MAXLEN 影响)
ACL @read、@list、@fast
命令标记 readonly、fast

官方说明:LPOS 报告列表中匹配元素的索引,默认从列表表头开始扫描并返回第一个匹配;返回的索引始终以表头为 0 基准,即使从表尾方向查找也一样。$TRAE_REF

二、基础示例

以下命令在测试实例的 redis-cli 中执行。文中结果是预期说明,未实际连接 Redis 运行。示例沿用官方文档的数据与结果。

redis 复制代码
DEL tutorial:{lpos}:mylist
RPUSH tutorial:{lpos}:mylist a b c 1 2 3 c c
LPOS tutorial:{lpos}:mylist c

预期结果:RPUSH 返回 8;LPOS 返回 (integer) 2,即第一个 "c" 的索引。列表索引从表头以 0 开始计数,a 是 0、b 是 1、c 是 2。

注意 LPOS 只查找不修改,执行后列表内容与长度不变,与 LREM 的"查找并删除"不同。

三、RANK 参数:从第几个匹配开始

列表中 "c" 出现了 3 次(索引 2、6、7)。RANK 用于指定以第几个匹配为返回目标:

redis 复制代码
LPOS tutorial:{lpos}:mylist c RANK -1
LPOS tutorial:{lpos}:mylist c RANK 2
LPOS tutorial:{lpos}:mylist c RANK 100

预期结果:RANK -1 从表尾倒数,返回最后一个匹配 (integer) 7;RANK 2 返回第二个匹配 (integer) 6;RANK 100 超出实际匹配次数,返回空值。

RANK 为 0 是无效值,报错 ERR RANK can't be zero. Use 1 to start searching from the first matching element in the head and negative ranks to start searching from the tail。

四、COUNT 参数:批量返回匹配

COUNT 把单个索引变为索引数组,返回从起点开始的前 N 个匹配:

redis 复制代码
LPOS tutorial:{lpos}:mylist c COUNT 2
LPOS tutorial:{lpos}:mylist c RANK -1 COUNT 2
LPOS tutorial:{lpos}:mylist c COUNT 0
LPOS tutorial:{lpos}:mylist c RANK 2 COUNT 3

预期结果:COUNT 2 返回 [2, 6];RANK -1 COUNT 2 从最后一个匹配开始继续向表头方向收集,返回 [7, 6];COUNT 0 返回全部匹配 [2, 6, 7];RANK 2 COUNT 3 从第二个匹配开始要 3 个但只剩 2 个,返回 [6, 7]。

要点:COUNT 模式下的顺序与搜索方向一致,负 RANK 时索引是倒序给出的;COUNT 0 表示"不限数量",而不是"返回 0 个"。

五、MAXLEN 参数:限制比较范围

MAXLEN 限制最多比较多少个元素,防止在大列表上全量扫描:

redis 复制代码
LPOS tutorial:{lpos}:mylist c COUNT 0 MAXLEN 3
LPOS tutorial:{lpos}:mylist c RANK -1 COUNT 0 MAXLEN 3

预期结果:第一条只比较表头前 3 个元素 a,b,c,在索引 2 命中后停止,返回 [2];第二条从表尾方向比较 3 个元素 c,c,3,命中索引 7 和 6 后到达比较上限,返回 [7, 6]。

MAXLEN 计的是"比较次数"而不是"返回的匹配数",负 RANK 时从表尾倒数比较。MAXLEN 0 表示不限制。

六、返回值与空结果的两种形态

调用模式 有匹配 无匹配
不带 COUNT 返回整数索引 返回空值(nil)
带 COUNT 返回索引数组 返回空数组
redis 复制代码
LPOS tutorial:{lpos}:mylist no-such
LPOS tutorial:{lpos}:mylist no-such COUNT 0
LPOS tutorial:{lpos}:mylist no-such RANK 5

预期结果:第一条返回 (nil);第二条返回空数组 (empty list or set);第三条在单结果模式下 RANK 超出匹配次数,同样返回 (nil)。

客户端代码必须区分这两种形态:判断"元素是否存在"适合用单结果模式判断 nil;收集全部位置适合用 COUNT 模式判断空数组。

七、边界情况与错误处理

场景 行为
Key 不存在 视为空列表,返回空值(或 COUNT 模式下的空数组)
Key 类型不是 List 报 WRONGTYPE
element 为空字符串 允许,可与列表中的空字符串元素匹配
RANK 为 0 报错 ERR RANK can't be zero...
COUNT 为负数 报错 ERR COUNT can't be negative
MAXLEN 为负数 报错 ERR MAXLEN can't be negative
参数选项拼写错误 报 ERR syntax error
Redis 版本低于 6.0.6 报 unknown command 错误
redis 复制代码
SET tutorial:{lpos}:str text
LPOS tutorial:{lpos}:str a
LPOS tutorial:{lpos}:mylist c RANK 0

预期结果:第一条在 String 类型上报 WRONGTYPE;第二条报 RANK 为 0 的错误。

八、与相近命令的区别

命令 方向 是否修改列表 说明
LPOS 按值查找,返回索引 否 6.0.6 起支持
LINDEX 按索引取元素 否 与 LPOS 互为反向:一个按值找位置,一个按位置取值
LINSERT 按值定位插入 是(+1) 需要 pivot 已存在
LSET 按索引覆盖元素 否(长度不变) 常与 LPOS 组合实现"查找并替换"
LREM 按值删除 是(-N) 可删除前 N 个匹配,无位置信息返回

组合用法:LPOS key target 拿到索引后 LSET key index new_value 即为精确替换;带 COUNT 的 LPOS 可先确认重复元素的全部位置,再逐个处理。LREM 只能按值从前/后删除指定数量,拿不到索引。

九、客户端示例

前提为已安装 redis-py 并准备好本地测试实例。redis-py 的 lpos 签名为 lpos(name, value, rank=None, count=None, maxlen=None),单结果返回 int 或 None,带 count 返回列表。

python 复制代码
import redis

r = redis.Redis(host="localhost", port=6379, decode_responses=True)
key = "tutorial:{lpos}:py"
try:
    r.delete(key)
    r.rpush(key, "a", "b", "c", "1", "2", "3", "c", "c")

    print(r.lpos(key, "c"))                     # 2
    print(r.lpos(key, "c", rank=-1))            # 7
    print(r.lpos(key, "c", count=0))            # [2, 6, 7]
    print(r.lpos(key, "c", rank=2, count=3))    # [6, 7]
    print(r.lpos(key, "c", count=0, maxlen=3))  # [2]
    print(r.lpos(key, "no-such"))               # None
    print(r.lpos(key, "no-such", count=0))      # []
finally:
    r.delete(key)
    r.close()

Java(Jedis)示例,选项参数使用 redis.clients.jedis.params.LPosParams:

java 复制代码
import redis.clients.jedis.params.LPosParams;

try (Jedis jedis = new Jedis("localhost", 6379)) {
    String key = "tutorial:{lpos}:java";
    jedis.del(key);
    jedis.rpush(key, "a", "b", "c", "1", "2", "3", "c", "c");

    System.out.println(jedis.lpos(key, "c"));
    // 2
    System.out.println(jedis.lpos(key, "c", new LPosParams().rank(-1)));
    // 7
    System.out.println(jedis.lpos(key, "c", new LPosParams().rank(2), 3));
    // [6, 7]
    jedis.del(key);
}

十、原子性与性能注意事项

只读与原子性:LPOS 是只读命令,不修改列表,可在副本节点执行分担读压力;单命令原子执行,结果反映某一时刻的列表状态。

慢命令风险 :无 MAXLEN 时最坏情况要比较整个列表(O(N)),Redis 处理命令是单线程的,在百万级元素列表上做 COUNT 0 会阻塞其他命令,属于典型慢命令。大列表上应尽量指定 MAXLEN 或缩小查找范围,并通过 SLOWLOG 观测。

事务与 Pipeline:LPOS 可在 MULTI/EXEC 和 Lua 脚本中正常使用;"LPOS 查位置 + LSET 修改"两条命令不是原子的,并发修改同一列表时需要用 WATCH 或 Lua 脚本包裹。

集群:LPOS 只涉及单个 Key,在 Redis Cluster 中没有跨槽限制。

十一、典型业务场景

查找并精确替换 :有序配置列表、轮播位等场景中,先用 LPOS key old_value 定位,再用 LSET 覆盖,比重建整个列表更轻量。

重复元素巡检 :用 COUNT 0 查出某元素的全部出现位置,评估是否需要去重,再配合 LREM 或 LSET 清理。

调试与观测:开发期快速确认元素是否在列表中、位于第几位,辅助排查 LPUSH/RPUSH 的顺序问题。

限流查找 :只想确认"最近 N 个元素里有没有它"时,用 MAXLEN 控制比较量,把开销从 O(N) 降到 O(N_prefix)。

十二、练习、排错与总结

练习:新建 tutorial:{lpos}:ex,用 RPUSH 写入 a b a a;执行 LPOS ex a 确认返回 0;LPOS ex a RANK -1 返回 3;LPOS ex a COUNT 0 返回 [0, 2, 3];LPOS ex a COUNT 0 MAXLEN 2 返回 [0];LPOS ex nosuch 返回空值,COUNT 0 模式返回空数组。

排错要点:返回空值或空数组时先确认元素值是否与写入时大小写、空格完全一致(精确字节匹配);报 unknown command 时检查 Redis 版本是否低于 6.0.6;报 RANK/COUNT/MAXLEN 相关错误时检查参数取值(RANK 非 0、COUNT 与 MAXLEN 非负);慢日志出现 LPOS 时加 MAXLEN 或改用其他结构。清理使用 DEL tutorial:{lpos}:mylist tutorial:{lpos}:str tutorial:{lpos}:py tutorial:{lpos}:java tutorial:{lpos}:ex。速记:6.0.6 起支持、按值查找返回 0 基索引、RANK 指定第几个匹配且负数从表尾倒数、COUNT 批量返回且 0 为全部、MAXLEN 限制比较元素数、单结果无匹配返回空值而 COUNT 模式返回空数组、只读不修改列表、大列表务必防全量扫描。

相关推荐
guo_wen_qiang1 小时前
云服务器redis主从复制-哨兵模式
运维·服务器·redis
for_ever_love__2 小时前
LangGraph State 设计:多节点之间怎么安全地共享数据
redis·mysql·状态模式·checkpoint·state·状态图·langgraph
大圣编蚕2 小时前
Redis 为什么快?现在还是单线程吗?
数据库·redis·缓存
Linux实战笔记2 小时前
记一次Redis分布式锁实现线上排查:Redlock算法与 Lua 脚本
redis·高并发·分布式锁·redlock 算法·lua 脚本
路多辛2 小时前
全能 Go Agent 框架 covonaut v1.1.5 发布:改进检查点、Token用量与缓存
缓存·agent·ai编程
轮子大叔3 小时前
Redis深入浅出
redis·缓存
海绵宝宝转agent4 小时前
2026-10-14算法+面经总结
java·笔记·算法·缓存
旋生万物4 小时前
分形自相似:微服务、缓存、Prompt 模板为什么长一样
人工智能·缓存·微服务·云原生·prompt
计算机就业还在扩大4 小时前
Redis中的setnx是原子性的?
数据库·redis·缓存