我是Redis的新手,现在如果键存在于另一个排序集中,则需要更新一个排序集中的集合。
我认为通过示例进行解释可能更清晰,可以说有两个排序的集合,如下所示:
set_1
{key_1:val_1, key_2:val_2, key_3:val_3}
set_2
{key_1:val_new_1, key_3:val_new_3, key_4:val_new_4}
现在,如果密钥存在于第二组中,那么我尝试更新第一组,因此结果应为:
set_1
{key_1:val_new_1, key_2:val_2, key_3:val_new_3}
我已经阅读了一段时间的Redis文档,似乎将他的SET命令与XX选项一起使用可能会有所帮助:
SET命令支持一组用于修改其行为的选项:XX-仅设置已存在的密钥。
但是有可能避免在第一组的每个条目上运行此命令吗?也许使用诸如zunionstore之类的东西?
该SET
命令仅适用于常规键,不适用于排序集。
在排序集中,您拥有得分成员对,因此示例中的键值对命名法有些混乱。我假设key_1, key_2, key_3, ...
是成员,val_1, val_2, ...
是分数。
让我们创建如下的排序集以查看解决方案:
> ZADD set_1 1 key_1 2 key_2 3 key_3
(integer) 3
> ZADD set_2 1001 key_1 1003 key_3 1004 key_4
(integer) 3
默认AGGREGATE
值为SUM
,这是我们将在所有范围内使用的。
我们将创建两个排序的集合,两者的交集分别为一个分数为set_1
,另一个分数为set_2
。
> ZINTERSTORE intersect_set_1 2 set_1 set_2 WEIGHTS 1 0
(integer) 2
> ZINTERSTORE intersect_set_2 2 set_1 set_2 WEIGHTS 0 1
(integer) 2
现在,我们为创建一个中间步骤集set_1
,其中,对于其中的那些,我们也将其分数设置为零set_2
:
> ZUNIONSTORE pre_set_1 2 set_1 intersect_set_1 WEIGHTS 1 -1
(integer) 3
现在,我们准备更新set_1,并进行以下操作的并集:
pre_set_1
:set_1
除了那些也set_2
设置为零的分数。intersect_set_2
:的交点set_1
和set_2
与的得分set_2
。这是最终命令:
> ZUNIONSTORE set_1 2 pre_set_1 intersect_set_2
(integer) 3
让我们看一下结果:
> ZRANGE set_1 0 -1 WITHSCORES
1) "key_2"
2) "2"
3) "key_1"
4) "1001"
5) "key_3"
6) "1003"
不要忘记清理:
> UNLINK pre_set_1 intersect_set_1 intersect_set_2
此解决方案不是最佳方案,因为它使用了多个中间步骤,存在成员之间添加到原始集中的风险,并且它使用了不必要的内存。
最佳解决方案是Lua脚本:
local set2 = redis.call('ZRANGE', KEYS[1], '0', '-1', 'WITHSCORES')
local set2length = table.getn(set2)
for i=1,set2length,2 do redis.call('ZADD', KEYS[2], 'XX', set2[i+1], set2[i]) end
return set2length/2
这循环进行set_2
,更新set_1
。注意XX
在ZADD
命令中的使用,仅在存在时进行更新。
用于:
EVAL "local set2 = redis.call('ZRANGE', KEYS[1], '0', '-1', 'WITHSCORES') \n local set2length = table.getn(set2) \n for i=1,set2length,2 do print(1) redis.call('ZADD', KEYS[2], 'XX', set2[i+1], set2[i]) end \n return set2length/2" 2 set_2 set_1
由于Redis具有单线程特性,因此Lua脚本是原子的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句