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'
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)
8条答案
按热度按时间lxkprmvk1#
我也要这么做。我想从列表中删除该元素,然后再添加它。如果元素不在列表中,Redis将返回0,因此没有错误
0aydgbwb2#
正如Tommaso Barbugli提到的,如果你只需要唯一的值,你应该使用集合而不是列表。see REDIS documentation SADD
如果要检查集合中是否存在值,可以使用SISMEMBER
u0sqgete3#
看起来你需要一个集合或一个排序的集合。
集合有O(1)的成员测试和强制唯一性。
avkwfej44#
如果你不能使用SET(如果你想实现一些阻塞的POP/PUSH列表功能),你可以使用一个简单的脚本:
这将返回您添加的脚本的SHA代码。
然后打电话:
何处
3e31bb17571f819bea95ca5eb5747a373c575ad9
(您添加的脚本的SHA代码)1
-是参数的数量(1是该函数的常数)test-list
-列表的名称myval
-需要添加的值如果添加了新项,则返回1,如果它已经在列表中,则返回0。
liwlm1x95#
在redis中使用
hexists
hexists命令可以设置此功能。piztneat6#
检查一个列表以查看其中是否存在一个成员是O(n)的,对于大列表来说,这可能会变得非常昂贵,并且肯定不是理想的。也就是说,其他人似乎都在给你选择。我只会告诉你如何做你要求做的事情,并假设你有很好的理由这样做。我将在Python中实现,假设你有一个名为
r
的Redis连接,一个名为some_list
的列表和一个名为new_item
的新项:pu82cl6c7#
我在添加到任务工作队列时遇到了这个问题,因为我想避免添加许多重复的任务。使用一个Redis集合(正如许多人所建议的那样)会很好,但是Redis集合没有像BRPOPLPUSH那样的“阻塞弹出”,所以它们不适合任务队列。
所以,这是我稍微不理想的解决方案(在Python中):
注意文档字符串中的警告。
如果你真的需要保证没有重复,另一种方法是在Redis管道中运行LREM,LPUSH,就像0xAffe的答案一样。这种方法导致较少的网络流量,但有重新排序列表的缺点。如果您不关心列表顺序,这可能是最好的一般答案。
yhxst69z8#
正如@Eli所说,检查列表中的存在是一个O(N)操作,这是昂贵的,特别是如果列表很大。我也面临着类似的问题。对我来说,使用SET不是一个选择,因为我需要在从列表中删除项目时保证插入顺序。Redis SETS以随机顺序删除/检索项目,这对我来说是一个交易破坏者。我想做的是在Redis中维护一个单独的HASH,只是为了在将项目添加到列表之前检查它是否已经存在。这意味着每当我在列表中添加一个项时,我必须将其添加到这个辅助数据结构(HASH)中,以支持O(1)查找来检查是否存在。我知道这是重复数据,但考虑到其他选项,额外的空间消耗可能看起来不那么糟糕。