2

How to get a list of members based on their ID from a sorted set instead of just one member?

I would like to build a subset with a set of IDs from the actual sorted set.

I am using a Ruby client for Redis and do not want to iterate one by one. Because there could more than 3000 members that I want to lookup.

Here is the issue tracker to a new command ZMSCORE to do bulk ZSCORE.

Raj
  • 22,346
  • 14
  • 99
  • 142
  • Consider using `MULTI`. There's no built-in multiple access for `ZSCORE`. Maybe indicate the language of your choice so this may be answered in a more specific way. – woozyking Mar 28 '16 at 13:54
  • @woozyking I am using Ruby client. Updated the question with more details. – Raj Mar 28 '16 at 14:16
  • You can use `MULTI` with Ruby, can't you? – Jordan Running Mar 28 '16 at 14:20
  • @Jordan I am using redis-objects, not sure how to do multi with that – Raj Mar 28 '16 at 14:21
  • 2
    You can use `MULTI`, and other exposed features provided by `redis-rb` which is what `redis-objects` depends on. You can actually use `pipeline` which may be fater than MULTI, provided your use case is simple enough https://github.com/redis/redis-rb#pipelining . Otherwise Lua scripting may be more powerful and overall efficient. – woozyking Mar 28 '16 at 14:25

1 Answers1

3

There is no variadic form for ZSCORE, yet - see the discussion at: https://github.com/antirez/redis/issues/2344

That said, and for the time being, what you could do is use a Lua script for that. For example:

local scores = {}
while #ARGV > 0 do
    scores[#scores+1] = redis.call('ZSCORE', KEYS[1], table.remove(ARGV, 1))
end
return scores

Running this from the command line would look like:

$ redis-cli ZADD foo 1 a 2 b 3 c 4 d
(integer) 4
$ redis-cli --eval mzscore.lua foo , b d
1) "2"
2) "4"

EDIT: In Ruby, it would probably be something like the following, although you'd be better off using SCRIPT LOAD and EVALSHA and loading the script from an external file (instead of hardcoding it in the app):

require 'redis'

script = <<LUA
    local scores = {}
    while #ARGV > 0 do
        scores[#scores+1] = redis.call('ZSCORE', KEYS[1], table.remove(ARGV, 1))
    end
    return scores
LUA

redis = ::Redis.new()
reply = redis.eval(script, ["foo"], ["b", "d"])

Lua script to get scores with member IDs:

local scores = {}
while #ARGV > 0 do
    local member_id = table.remove(ARGV, 1)
    local member_score = {}
    member_score[1] = member_id
    member_score[2] = redis.call('ZSCORE', KEYS[1], member_id)
    scores[#scores + 1] = member_score
end
return scores
Raj
  • 22,346
  • 14
  • 99
  • 142
Itamar Haber
  • 47,336
  • 7
  • 91
  • 117