8

I need to get all score available for a redis sorted set.

redis>  ZADD myzset 10 "one"

(integer) 1

redis>  ZADD myzset 20 "two"

(integer) 1

redis>  ZADD myzset 30 "three"

(integer) 1

Now I want to retrieve all score for myzset, ie. 10,20,30.

biztiger
  • 1,447
  • 4
  • 23
  • 40

4 Answers4

8

EDIT: Since your problem with the size of the values wasn't obvious before, I did some additional research.

There is according to the current documentation no way to get just the scores from a sorted set.

What you'll need to do to get just the scores is to simultaneously add them to a separate set and get them from there when needed.

What you should probably do first though is to try to map your problem differently into data structures. I can't tell from your question why you'd need to get the scores, but there may be other ways to structure the problem that will map better to Redis.

--

I'm not sure there is any way to get all scores without getting the keys, but ZRANGE will at least get the information you're looking for;

redis>  ZADD myzset 10 "one"
(integer) 1

redis>  ZADD myzset 20 "two"
(integer) 1

redis>  ZADD myzset 30 "three"
(integer) 1

redis> ZRANGE myzset 0 -1 WITHSCORES
["one","10","two","20","three","30"]
Joachim Isaksson
  • 176,943
  • 25
  • 281
  • 294
5

One way to address this problem is to use server-side Lua scripting.

Consider the following script:

local res = {}
local result = {}
local tmp = redis.call( 'zrange', KEYS[1], 0, -1, 'withscores' )
for i=1,#tmp,2 do
   res[tmp[i+1]]=true
end
for k,_ in pairs(res) do
   table.insert(result,k)
end
return result

You can execute it by using the EVAL command.

It uses the zrange command to extract the content of the zset (with scores), then it builds a set (represented with a table in Lua) to remove redundant scores, and finally build the reply table. So the values of the zset are never sent over the network.

This script has a flaw if the number of items in the zset is really high, because it copies the entire zset in a Lua object (so it takes memory). However, it is easy to alter it to iterate on the zset incrementally (20 items per 20 items). For instance:

local res = {}
local result = {}
local n = redis.call( 'zcard', KEYS[1] )
local i=0
while i<n do
   local tmp = redis.call( 'zrange', KEYS[1], i, i+20, 'withscores' )
   for j=1,#tmp,2 do
      res[tmp[j+1]]=true
      i = i + 1
   end
end
for k,_ in pairs(res) do
   table.insert(result,k)
end
return result

Please note I am a total newbie in Lua, so there are perhaps more elegant ways to achieve the same thing.

Didier Spezia
  • 70,911
  • 12
  • 189
  • 154
1

You need to pass the optional argument WITHSCORES. See documentation here:

ZREVRANGE key start stop [WITHSCORES] Return a range of members in a sorted set, by index, with scores ordered from high to low

Andrew U
  • 739
  • 7
  • 10
0

When it comes to ruby the following command will do

redis.zrange("zset", 0, -1, :with_scores => true)
# => [["a", 32.0], ["b", 64.0]]

source Ruby Docs

mgs
  • 404
  • 4
  • 15