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

时间:2012-01-17 17:37:16

标签: list lua redis

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

实施例

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

{"dan","eduardo","pedro"}

索引将是:

0 : "dan"
1 : "eduardo"
2 : "pedro"

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

喜欢“eduardo”并回到'1'。

如果可能的话,你会怎么做?

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

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

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

此外没有其他限制因此必须可以单独使用redis,没有外部进程等,但是如果你想使用带有lua的EVAL命令,那就去吧。

修改

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

6 个答案:

答案 0 :(得分:8)

我不知道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

查看有关EVAL命令的http://redis.io/commands/eval进一步文档。

答案 1 :(得分:8)

使用有序集来实现队列。

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

> ZADD queue 1326990501 foo 1326990502 bar 1326990503 baz 1326990504 qux
(integer) 4

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

FIFO:

> ZRANGE queue 0 0
"foo"

LIFO:

> ZREVRANGE queue 0 0
"qux"

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

> ZRANK queue bar
(integer) 1

答案 2 :(得分:6)

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

虽然有人做了一些非常好的remarks on why such operation would make sense,但看起来Salvatore很快就不会实施它。

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

  • 使用自定义lua脚本在列表中查找索引;
  • 使用排序集(而不是列表),时间戳作为分数,[{ "id": 1, "guest_first_name": "Jon", "guest_last_name": "Doe", "guest_do_b": "1954-07-13T00:00:00+0100", "text": "Jon Doe" }, { "id": 2, "guest_first_name": "Janne", "guest_last_name": "Doe", "guest_do_b": "1960-01-14T00:00:00+0100", "text": "Janne Doe" }] 作为索引。

由于第一个是ZRANK而后者只是O(N),你可能会知道哪一个优于另一个。

Anyway I decided to put to the test *:

O(log(N))

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

*在Windows 7上,Redis 2.8(MSOpenTech port),.NET 4,打开了编译器优化并StackExchange.Redis 1.0.488。

答案 3 :(得分:4)

根据redis.io

问题列表中的票证140

功能请求:lRank

“嗨,这个命令可能不会实现,因为它既是O(N)命令,也只是在数据布局设计中出现错误时才会感觉到需要。” Salvatore Sanfilippo上的https://github.com/antirez/redis/issues/140

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

所以最重要的是没有办法找出列表中除了使用lua脚本之外的项目的索引。

然而,根据实施情况,即数据设计,最好考虑排序集而不是列表。

答案 4 :(得分:3)

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

documentation

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

因此,对于您来说,列表{"dan","eduardo","pedro"}的键为users

LPOS users eduardo

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

答案 5 :(得分:1)

使用排序集(ZADD等),您可以使用ZRANK

编辑:我在下面的旧答案不起作用,因为您的列表会更改(尽管如此),列表只会使用RPUSH进行更新。

您可以使用值(或其哈希值)将索引存储为键:

set listvalue listindex

为了使redis井井有条,你可以在列表名前加上这些键的前缀:

set listname:listvalue listindex