仅当Redis列表没有';列表中不存在吗?

仅当Redis列表没有';列表中不存在吗?,redis,Redis,我正在尝试向列表中添加值,但前提是尚未添加该值 是否有命令执行此操作,或者是否有方法测试列表中是否存在值 谢谢 看起来您需要一个集合或排序集合 集合具有O(1)成员身份测试和强制唯一性。使用redis中的hexists命令在集合中可以使用此功能。检查列表以查看其中是否存在成员是O(n),这对于大列表来说可能会非常昂贵,而且绝对不理想。也就是说,其他人似乎都在给你选择。我会告诉你如何去做你要求做的事情,并假设你有充分的理由按照你现在的方式去做。我将用Python来实现,假设您有一个名为r的Redi

我正在尝试向列表中添加值,但前提是尚未添加该值

是否有命令执行此操作,或者是否有方法测试列表中是否存在值


谢谢

看起来您需要一个集合或排序集合


集合具有O(1)成员身份测试和强制唯一性。

使用redis中的
hexists
命令在集合中可以使用此功能。

检查列表以查看其中是否存在成员是O(n),这对于大列表来说可能会非常昂贵,而且绝对不理想。也就是说,其他人似乎都在给你选择。我会告诉你如何去做你要求做的事情,并假设你有充分的理由按照你现在的方式去做。我将用Python来实现,假设您有一个名为
r
的Redis连接,一些列表名为
some\u list
,还有一些要添加的新项名为
new\u item

lst = r.lrange(list_name, -float('Inf'), float('Inf'))
if new_item not in lst:
     r.rpush(list_name, new_item)
我也需要这样做。 我考虑从列表中删除元素,然后再次添加它。如果元素不在列表中,redis将返回0,因此没有错误

lrem mylist 0 myitem
rpush mylist myitem 

正如Tommaso Barbugli提到的,如果只需要唯一值,则应该使用集合而不是列表。

如果要检查集合中是否存在值,可以使用


我在添加到任务工作队列时遇到这个问题,因为我希望避免添加许多重复的任务。使用Redis集合(正如许多人所建议的)会很好,但是Redis集合没有像BRPOPLPUSH那样的“阻塞pop”,所以它们不适合任务队列

因此,这里是我的稍微不理想的解决方案(在Python中):

注意docstring中的注意事项

如果您需要真正保证没有重复,那么另一种方法是在Redis管道中运行LREM、LPUSH,如0xaff的回答所示。这种方法会减少网络流量,但缺点是会重新排列列表。如果你不关心列表顺序,这可能是最好的一般答案。

如果你不能使用集合(如果你想实现一些阻止弹出/推送列表功能),你可以使用一个简单的脚本:

script load 'local exists = false; for idx=1, redis.call("LLEN",KEYS[1]) do if (redis.call("LINDEX", KEYS[1], idx) == ARGV[1]) then exists = true; break; end end; if (not exists) then redis.call("RPUSH", KEYS[1], ARGV[1]) end; return not exists or 0'
这将返回您添加的脚本的SHA代码

然后打电话:

evalsha 3e31bb17571f819bea95ca5eb5747a373c575ad9 1 test-list myval
在哪里

  • 3e31bb17571f819bea95ca5eb5747a373c575ad9
    (您添加的脚本的SHA代码)
  • 1
    -是参数数量(1是此函数的常数)
  • 测试列表
    -列表的名称
  • myval
    -需要添加的值

如果添加了新项,则返回1;如果已在列表中,则返回0。

有任何原因不能使用集合吗?()@Dogbert blocking Pop
LRANGE 0-1
对于获取整个列表不是更好吗?不幸的是,这是最好的选择,尽管它容易受到比赛条件的影响。@Salgat可以将其包装在Lua脚本中您是对的@contactmatt Lua脚本是一种解决方法。有点老套,但提供了一个原子保证你的行动是什么。这必须是选定的答案。很好的解决方案。但是要注意,当它将元素移动到列表末尾时,不要将其用于FIFO队列
def pushOnlyNewItemsToList(redis, list_name, items):
    """ Adds only the items that aren't already in the list.
    Though if run simultaneously in multiple threads, there's still a tiny chance of adding duplicate items.
    O(n) on the size of the list."""
    existing_items = set(redis.lrange(list_name,0,-1))
    new_items = set(items).difference(existing_items)
    if new_items:
        redis.lpush(list_name, *new_items)
script load 'local exists = false; for idx=1, redis.call("LLEN",KEYS[1]) do if (redis.call("LINDEX", KEYS[1], idx) == ARGV[1]) then exists = true; break; end end; if (not exists) then redis.call("RPUSH", KEYS[1], ARGV[1]) end; return not exists or 0'
evalsha 3e31bb17571f819bea95ca5eb5747a373c575ad9 1 test-list myval