在redis列表中,通过值获取一个项的索引。
我创建了一个 redis 列表,目前将其用作队列,有时会反转。我的问题是,我想通过值获取队列/列表中项的索引。
示例
如果我有一个值如下的列表:
{"dan","eduardo","pedro"}
索引将是:
0 : "dan"
1 : "eduardo"
2 : "pedro"
我想通过传递值来获得该值在我的列表中的索引。
像 "eduardo",返回 '1'。
如果可能的话,应该如何实现?
还有一件事我应该说的是,我正在向我的列表执行队列命令,从顶部删除项并将它们添加到底部。
我目前正在使用 node.js 0.6.6 和最新的 redis 模块以及最新的 redis 版本 2.4.4。
如果您希望仅在 redis-cli 中使用,则可以提供解决方案。
另外,没有任何限制,只要可能性仅在 redis 中完成,不使用外部进程等,但是如果您想使用 lua 的 EVAL 命令,请使用它。
编辑
另外,我认为我的答案可能在排序集上,而不在队列上。
原文链接 https://stackoverflow.com/questions/8899111
我不知道关于 nodejs 客户端的细节,但以下是使用 lua 实现的一个非常简单的 indexOf 命令。
在我的 indexof.lua
文件中,我有以下代码:
local key = KEYS[1]
local obj = ARGV[1]
local items = redis.call('lrange', key, 0, -1)
for i=1,#items do
if items[i] == obj then
return i - 1
end
end
return -1
让我们向 mylist
推送一些值。
> rpush mylist foo bar baz qux
(integer) 4
我们可以使用 lua 脚本在列表中查找任何值的索引。这个命令是 O(N)。
$ redis-cli --eval indexof.lua mylist , bar
(integer) 1
bar
的索引为 1。
> lindex mylist 1
"bar"
nil
的索引为 -1。
$ redis-cli --eval indexof.lua mylist , nil
(integer) -1
请查看 http://redis.io/commands/eval 中关于 EVAL 命令的更多文档。
使用有序集合来实现队列。
添加成员并将时间戳用作得分。
> ZADD queue 1326990501 foo 1326990502 bar 1326990503 baz 1326990504 qux
(integer) 4
您可以通过使用 ZRANGE(FIFO) 和 ZREVRANGE(LIFO) 返回成员。
FIFO:
> ZRANGE queue 0 0
"foo"
LIFO:
> ZREVRANGE queue 0 0
"qux"
要查找成员的索引,请使用 ZRANK。 ZRANK 操作的时间是 O(log(N))
> ZRANK queue bar
(integer) 1
按照redis.io的问题列表上的第140个票据
功能需求:lRank
"嗨,这个命令可能不会被实现,因为它是一个 O(N) 命令,通常只有在数据布局设计存在一些错误时才感觉需要。" 由 Salvatore Sanfilippo 在 https://github.com/antirez/redis/issues/140 上说。
我不太确定为什么想要按值查找项目的索引可能会是数据设计中的错误。 然而,他明确指出,你可以使用Lua代码和/或排序集合。
因此,它的核心是,没有其他方法来查找列表中项的索引,除非使用Lua脚本。
然而,根据实现,即数据设计,考虑使用排序集合可能会更好。
由现在开始,您可以通过 Redis 不支持此操作(伤心的脸)看出来。
虽然某人对为什么这样的操作有意义发表了一些不错的 评论,但看起来 Salvatore 不会很快实现它。
基本上有两种解决方法(如其他答案所指出的):
- 使用自定义 lua 脚本找到列表中的索引;
- 使用排序集合(而不是列表)以时间戳为分数和
ZRANK
为索引。
由于第一个是 O(N)
,而后者仅是 O(log(N))
,因此您可以知道哪个表现更好。
无论如何,我决定 测试一下*:
â•”â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•╦â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•╦â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•—
â•‘ â•‘ 带有 ZRANK 的排序集合 â•‘ 使用 lua 脚本的列表 â•‘
â• â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•╬â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•╬â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•£
â•‘ 1000 个元素 â•‘ 0.0638264 秒 â•‘ 0.2723238 秒 â•‘
â• â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•╬â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•╬â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•£
â•‘ 10000 个元素 â•‘ 00.4484714 秒 â•‘ 41.0661683 秒 â•‘
╚â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•©â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•©â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
是的,仅有一万个元素需要长达 41 秒的时间。
\* 在 Windows 7 上,使用 Redis 2.8(MSOpenTech 端口),.NET 4 和启用编译器优化以及 StackExchange.Redis 1.0.488。
使用 LPOS 命令(从 Redis 版本 6.0.6 开始可用)可以获取 redis 列表中元素的索引。
从文档中获取:
- 命令 -
LPOS key element [FIRST rank] [COUNT num-matches] [MAXLEN len]
- 该命令返回 Redis 列表中匹配元素的索引。
- 默认情况下,当没有给出选项时,它将从头到尾扫描列表,查找“element”的第一个匹配。如果找到元素,则返回其索引(列表中基于零的位置)。否则,如果找不到匹配项,就返回 NULL。
因此,在您的情况下,列表 {"dan","eduardo","pedro"}
的键为 users
LPOS users eduardo
必须返回 1。我个人还没有尝试在 lua 脚本中使用它,因此没有提供脚本,但我认为应该很简单。
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
使用排序集合(ZADD等)可以使用ZRANK。
编辑:我的旧答案不起作用,因为你的列表会发生变化,尽管只有使用RPUSH增长的列表。
您可以将索引与值(或其哈希)一起存储为键:
set listvalue listindex
为了保持您的Redis组织有序,您可以在这些键前缀中加上列表名称:
set listname:listvalue listindex