Как в Redis отделить записи от 1-го набора, исключив записи из 2-го отсортированного набора?

У меня есть два отсортированных набора, я хочу отделить записи от 1-го набора и сохранить в новом списке/отсортированном наборе, исключив записи из 2-го отсортированного набора.

Ниже приведен пример:

набор1: 1,2,3,4,5 набор2: 3,5,7,8,9

выход: 1,2,4

EDIT: я нашел способ загрузить скрипт и использовать 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);
      });
 }
);

person Suyog Kale    schedule 29.12.2016    source источник
comment
Возможный дубликат Как получить DIFF в отсортированном наборе   -  person Lorenzo Belli    schedule 29.12.2016


Ответы (3)


Проверьте этот вопрос:

Что вы можете сделать, так это сначала создать временный набор с помощью 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"
person Lorenzo Belli    schedule 29.12.2016
comment
Для меня работает следующий обходной путь: 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 result 0 0 DEL temp ZRANGE result 0 -1 1) 2 2) 3 3) 4 ВЫ ДУМАЕТЕ, ЧТО ПРОБЛЕМА ПРОИЗВОДИТЕЛЬНОСТИ? - person Suyog Kale; 29.12.2016
comment
Ха - это тоже мое :) было бы интересно сравнить это со скриптом Lua - person Itamar Haber; 29.12.2016

было здорово иметь дискуссию ранее. Как и было обещано, другой подход к решению этой проблемы — использование 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"
person Itamar Haber    schedule 29.12.2016
comment
Поскольку я новичок в Redis и сценариях lua, мне трудно понять, как я могу развернуть свои сценарии lua на redislabs, размещенных в redis db. - Вызов сценария lua из приложения моего узла Любая ссылка или шаги могут мне помочь. JFYI: Сейчас я использую бесплатную версию redislabs, так как все еще оцениваю ее. - person Suyog Kale; 30.12.2016
comment
не могли бы вы дать мне скрипт для исключения записей set1, которые существуют в set2? Кроме того, что у нас есть миллионы записей. вызовет ли это проблемы с производительностью? - person Suyog Kale; 30.12.2016

Я думаю, вы ищете SDIFF:

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

https://redis.io/commands/sdiff

Однако для отсортированных множеств нет эквивалента.

person Not_a_Golfer    schedule 29.12.2016
comment
Нет, я хочу использовать отсортированные наборы. Я не смог найти для этого ZDIFF, какой-нибудь обходной путь? - person Suyog Kale; 29.12.2016
comment
Вы можете написать его на Lua или реализовать в виде модуля. - person Not_a_Golfer; 29.12.2016
comment
@Not_a_Golfer, не могли бы вы рассказать об этом подробнее? Почему Луа? Модуль чего? - person Lorenzo Belli; 29.12.2016
comment
@LorenzoBelli Есть два способа добавить функциональность в Redis: сценарии Lua, которые запускаются внутри сервера, или модули, написанные на C, которые могут его расширить. Оба могут реализовать функциональность ZDIFF. На самом деле, я не возражаю быстро написать модуль, который выполняет ZDIFF, просто для демонстрации. Lua будет намного медленнее, но оба будут работать. - person Not_a_Golfer; 29.12.2016