SRANDMEMBER从Set返回一个随机成员。 SPOP从Set中删除随机成员。 SMOVE将指定成员从一个Set移动到另一个Set。
如何在一次拍摄中将随机成员从一个集合移动到另一个集合? 我不想激活一个SRANDMEMBER,等待它的结果,然后调用SMOVE。
我尝试使用EVAL脚本,但它不能与SRANDMEMBER一起使用,发出“在非确定性命令后不允许写入命令”。
操作必须是O(1)和原子。
答案 0 :(得分:2)
Redis可以防止Lua脚本中的随机写入,从而不会破坏复制(脚本也会在从属服务器上进行评估)。也就是说,这是一个伪随机解决方案:
local t = redis.call("SMEMBERS", KEYS[1])
local n = redis.call("SCARD", KEYS[1])
local r = math.random(1, n+1)
redis.call("SMOVE", KEYS[1], KEYS[2], t[r])
return t[r]
注意:
从3.2开始,您可以通过先验地调用redis.replicate_commands()
来更随机。
答案 1 :(得分:0)
我只是在写出解决方案(对于redis v3.2 +,由Itamar Haber的回答暗示。对于那些希望复制粘贴工作而不是实际学习lua的人来说(就像我!)
redis.replicate_commands() -- needed since we call SRANDMEMBER below
local value = redis.call('SRANDMEMBER', KEYS[1])
if value then
redis.call('SMOVE', KEYS[1], KEYS[2], value)
end
return value
在我的情况下,我正在使用pyredis,所以我写了这个函数:
def redis_smoverand(redis):
"""Register our smoverand() script on the given redis instance.
smoverand() selects a random member from a set, moves it to another set atomically, and returns
it. Usage:
redis_smoverand(redis)('source_set', 'dest_set')
The script is cached the first time this function is called."""
if not getattr(redis, '_smoverand', None):
lua = """
redis.replicate_commands() -- needed since we call SRANDMEMBER below
local value = redis.call('SRANDMEMBER', KEYS[1])
if value then
redis.call('SMOVE', KEYS[1], KEYS[2], value)
end
return value
"""
redis._smoverand = redis.register_script(lua)
return lambda k1, k2: redis._smoverand(keys=(k1, k2), args=())