在redis列表中按值获取项目的索引

dmp*_*lla 12 lua list redis

我有一个我创建的redis列表,我现在将它用作队列,偶尔会反转一次.我的问题是我希望能够按值获取该队列/列表中项目的索引.

如果我有一个包含以下值的列表:

{"dan","eduardo","pedro"}
Run Code Online (Sandbox Code Playgroud)

索引将是:

0 : "dan"
1 : "eduardo"
2 : "pedro"
Run Code Online (Sandbox Code Playgroud)

我希望能够通过传入值来获取列表中该值的索引.

像"eduardo"一样回归'1'.

这样可能吗,你会怎么做?

我还应该说的是,我正在对我的列表执行队列命令,从顶部删除项目并在底部添加它们.

我目前正在使用node.js 0.6.6和最新的redis模块以及最新的redis版本2.4.4.

我很高兴在redis-cli中找到解决方案.

此外没有其他约束,那么必须可以单独使用redis,没有外部进程等,但是如果你想使用带有lua的EVAL命令去做它.

编辑

另外我认为我的答案可能是排序集而不是队列.

Sim*_*ann 9

我不知道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
Run Code Online (Sandbox Code Playgroud)

让我们推几个值到一个mylist.

> rpush mylist foo bar baz qux
(integer) 4
Run Code Online (Sandbox Code Playgroud)

我们可以使用lua脚本来查找列表中任何值的索引.命令是O(N).

$ redis-cli --eval indexof.lua mylist , bar
(integer) 1
Run Code Online (Sandbox Code Playgroud)

指数bar为1

> lindex mylist 1
"bar"
Run Code Online (Sandbox Code Playgroud)

index nil为-1

$ redis-cli --eval indexof.lua mylist , nil
(integer) -1
Run Code Online (Sandbox Code Playgroud)

查看有关EVAL命令的http://redis.io/commands/eval更多文档.

  • 这是Lua用法的一个有趣例子.但是,成本是列表的完整副本,加上Lua中的线性搜索.它只能应用于小型列表.对于大型列表,它将冻结Redis循环几秒钟并消耗太多内存. (2认同)

Sim*_*ann 9

使用有序集来实现队列.

添加成员并使用时间戳作为分数.

> ZADD queue 1326990501 foo 1326990502 bar 1326990503 baz 1326990504 qux
(integer) 4
Run Code Online (Sandbox Code Playgroud)

您可以分别使用ZRANGE和ZREVRANGE以FIFO和LIFO顺序返回成员.

FIFO:

> ZRANGE queue 0 0
"foo"
Run Code Online (Sandbox Code Playgroud)

LIFO:

> ZREVRANGE queue 0 0
"qux"
Run Code Online (Sandbox Code Playgroud)

要查找成员的索引,请使用ZRANK.ZRANK op是O(log(N))

> ZRANK queue bar
(integer) 1
Run Code Online (Sandbox Code Playgroud)


shr*_*sha 9

可以使用 LPOS 命令获取 Redis 列表中元素的索引(自版本 6.0.6 起可用

文档来看,

  • 命令 -LPOS key element [FIRST rank] [COUNT num-matches] [MAXLEN len]
  • 该命令返回 Redis 列表中匹配元素的索引。
  • 默认情况下,当没有给出任何选项时,它将从头到尾扫描列表,寻找“element”的第一个匹配项。如果找到该元素,则返回其索引(列表中从零开始的位置)。否则,如果未找到匹配项,则返回 NULL。

{"dan","eduardo","pedro"}所以在你的情况下,对于带有键的列表users

LPOS users eduardo
Run Code Online (Sandbox Code Playgroud)

必须返回 1。我个人没有尝试在 lua 脚本中使用它,因此没有提供脚本,但我相信应该是直接的。


tal*_*les 7

正如您现在所知,Redis不支持此类操作(悲伤的表情).

虽然有人对为什么这样的操作有意义做了一些非常好的评论,但看起来Salvatore不会很快实现它.

基本上有两种解决方法(如其他答案所指出的):

  • 使用自定义lua脚本在列表中查找索引;
  • 使用带有时间戳作为分数和ZRANK索引的有序集(而不是列表).

因为第一个O(N)和后者只是O(log(N))你可以告诉哪一个优于另一个.

无论如何,我决定进行测试*:

?????????????????????????????????????????????????????????????????
?                ? Sorted Set with ZRANK ? List with lua script ?
?????????????????????????????????????????????????????????????????
?  1000 elements ?   0.0638264 seconds   ?   0.2723238 seconds  ?
?????????????????????????????????????????????????????????????????
? 10000 elements ?   00.4484714 seconds  ?  41.0661683 seconds  ?
?????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

是的,只有一万个元素,这是惊人的41秒.

*在Windows 7,Redis的2.8(MSOpenTech端口),.NET 4的编译器优化接通和StackExchange.Redis 1.0.488.


dmp*_*lla 5

根据 redis.io 问题列表中的 Ticket 140

功能请求:lRank

“嗨,这个命令可能不会被实现,因为它既是一个 O(N) 命令,又是一个通常只有在数据布局设计中出现错误时才需要的命令。” 作者:Salvatore Sanfilippohttps://github.com/antirez/redis/issues/140

我不太清楚为什么以及如何想要按值找出项目的索引可能是数据设计中的错误。然而他明确表示你可以使用 lua 代码和/或排序集。

因此,除了使用 lua 脚本之外,没有其他方法可以找到列表中项目的索引。

然而,根据实现(即数据设计),考虑排序集而不是列表可能会更好。