Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redis: Get all score available for a sorted set

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.

like image 214
biztiger Avatar asked Jan 23 '13 18:01

biztiger


People also ask

What is score in Redis sorted set?

Redis Sorted Sets are similar to Redis Sets with the unique feature of values stored in a set. The difference is, every member of a Sorted Set is associated with a score, that is used in order to take the sorted set ordered, from the smallest to the greatest score.

What is ZSET in Redis?

ZSET is a short name for Redis Sorted Set, a Redis data type documented here. Each key in a sorted set has multiple values inside, associated with a floating value score.

How does Redis sorted set work?

Sorted set is essentially a unique collection of ordered Redis Strings that have a numeric score associated with them. Ordering is based on scores and the string lexicographical order (more on this later). The strings must be unique while the scores might be repeated.

Is member sorted set Redis?

Sorted Set is similar to the Set data structure in Redis. Members can be a list of non-repeating strings. The only difference is that each member is associated with a score, a floating-point number that provides a sorting order for the Sorted Set. Members are always sorted from the smallest to the greatest score.


2 Answers

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"]
like image 55
Joachim Isaksson Avatar answered Sep 23 '22 02:09

Joachim Isaksson


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.

like image 41
Didier Spezia Avatar answered Sep 19 '22 02:09

Didier Spezia