【问题标题】:In Redis how to separate records from 1st set by excluding records from 2nd sorted sets.?在 Redis 中,如何通过排除第二个排序集中的记录来将记录与第一组分开。?
【发布时间】:2016-12-29 10:06:36
【问题描述】:

我有两个排序集,我想将记录与第一个集分开,并通过排除第二个排序集中的记录来存储在新列表/排序集中。

下面是一个例子:

set1: 1,2,3,4,5 set2: 3,5,7,8,9

输出:1,2,4

编辑: 我已经找到了加载脚本并使用 eval 从 nodejs 执行脚本的方法。

奇怪的是,当我执行您的脚本时,即使处理 5-10 条记录也需要 1 秒钟的时间,这让我怀疑如果我有数千条记录,它的可扩展性有多大。

以下是我的示例 nodejs 代码:

hsetxx = 'redis.call("ZINTERSTORE","temp",2,"set11","set21","weights",1,0) redis.call("ZUNIONSTORE","result",2,"set11","temp","weights",1,-1) redis.call("ZREMRANGEBYSCORE","result",0,0)';

var redis = require('redis');
var client = redis.createClient('14470', connection);

client.on('connect', function() {
    console.log('Connected to Redis');
});

client.script('load',hsetxx,function(err, result) {
     console.log(err+'------------'+result);
 });

client.zadd('set11', 1,1,1,2,1,3,1,4,1,5);
client.zadd('set21', 1,1,1,5);

client.evalsha(
 '39c0da298cab6a6223b4d1e8222cf6d6a84e67b1', //lua source 
 0,
 function(err, result) {
     client.zrange('result', 0, -1, function(err, result) {
          console.log(err+'------------'+result);
      });
 }
);

【问题讨论】:

标签: redis sortedset set-difference


【解决方案1】:

查看this问题:

您可以首先使用 ZUNIONSTORE 创建一个临时集,然后 将相交的分数设置为 0。然后做一个不包括 0 的范围, 例如:

127.0.0.1:6379> ZADD all 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> SADD disabled two
(integer) 1
127.0.0.1:6379> ZUNIONSTORE tmp 2 all disabled WEIGHTS 1 0 AGGREGATE MIN
(integer) 3
127.0.0.1:6379> ZREVRANGEBYSCORE tmp +inf 1 WITHSCORES
1) "three"
2) "3"
3) "one"
4) "1"

【讨论】:

  • 以下解决方法对我有用: ZADD key1 1 1 1 2 1 3 1 4 1 5 ZADD key2 1 1 1 5 ZINTERSTORE temp 2 key1 key2 weights 1 0 ZUNIONSTORE result 2 key1 temp weights 1 -1 ZREMRANGEBYSCORE结果 0 0 DEL temp ZRANGE 结果 0 -1 1) "2" 2) "3" 3) "4" 你认为有任何性能问题吗?
  • 哈 - 这也是我的 :) 将其与 Lua 脚本进行比较会很有趣
【解决方案2】:

很高兴能早点进行讨论。正如所承诺的,另一种应对挑战的方法是使用 Lua 和 Redis 的EVAL。我不知道它的性能如何,但这是一个模仿 SDIFF 但用于排序集的(不太经过测试的)脚本:

~/src/redis-lua-scripts$ cat zdiff.lua 
-- ZDIFF key [key ...]
-- Returns the elements in the first key that are also present in all other keys

local key = table.remove(KEYS,1)
local elems = redis.call('ZRANGE', key, 0, -1)
local reply = {}

if #KEYS > 0 and #elems > 0 then
  for i, e in ipairs(elems) do
    local exists = true
    for j, k in ipairs(KEYS) do
      local score = redis.call('ZSCORE', k, e)
      if not score then
        exists = false
        break
      end
    end
    if exists then
      reply[#reply+1] = e
    end
  end
end

return reply
~/src/redis-lua-scripts$ redis-cli SCRIPT LOAD "`cat zdiff.lua`"
"e25d895f05dc638be87d13aed64e8d5780f17c99"
~/src/redis-lua-scripts$ redis-cli ZADD zset1 0 a 0 b 0 c 0 d 0 e
(integer) 5
~/src/redis-lua-scripts$ redis-cli ZADD zset2 0 a
(integer) 1
~/src/redis-lua-scripts$ redis-cli ZADD zset3 0 a 0 b
(integer) 2
~/src/redis-lua-scripts$ redis-cli EVALSHA e25d895f05dc638be87d13aed64e8d5780f17c99 3 zset1 zset2 zset3
1) "a"

【讨论】:

  • 由于我是 Redis 和 lua 脚本的新手,我很难理解 - 如何在 redislabs 托管的 redis db 上部署我的 lua 脚本。 - 从我的节点应用程序调用 lua 脚本任何参考或步骤都可以帮助我很多。 JFYI:我现在正在使用免费版的 redislabs,因为我还在评估它。
  • 你能给我脚本来排除set2中存在的set1记录吗?还有我们拥有数百万条记录。会导致性能问题吗?
【解决方案3】:

我认为您正在寻找 SDIFF:

key1 = {a,b,c,d}
key2 = {c}
key3 = {a,c,e}
SDIFF key1 key2 key3 = {b,d}

https://redis.io/commands/sdiff

但是,排序集没有等价物。

【讨论】:

  • 不,我想使用排序集。我找不到 ZDIFF,有什么解决方法吗?
  • 可以用 Lua 编写,也可以作为模块实现。
  • @Not_a_Golfer 你能详细说明一下吗?为什么是卢亚?什么模块?
  • @LorenzoBelli 有两种方法可以向 redis 添加功能 - 在服务器内部运行的 Lua 脚本,或者用 C 编写的可以扩展它的模块。两者都可以实现 ZDIFF 的功能。事实上,我不介意快速编写一个执行 ZDIFF 的模块来演示它。 Lua 会慢很多,但两者都可以。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 2020-07-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多