Redis: Is it possible sort ordered set result with same score by other key value

Bruce Dou picture Bruce Dou · May 2, 2012 · Viewed 8k times · Source
ZADD myset 1 ad1
ZADD myset 1 ad2

SET order:ad1 1
SET order:ad2 2

How to sort firstly by ordered set score then the order value?

Answer

Didier Spezia picture Didier Spezia · May 2, 2012

If you want to store a result (not altering the way data are stored), then you can use the SORT command. It can be applied to zset.

For instance:

> zadd myset 1 albert
> zadd myset 1 joseph
> zadd myset 4 bertrand
> zadd myset 2 casimir
> zadd myset 3 alfred

You can sort by value:

> sort myset alpha
1) "albert"
2) "alfred"
3) "bertrand"
4) "casimir"
5) "joseph"

You can sort by score AND value:

> zrange myset 0 -1
1) "albert"
2) "joseph"
3) "casimir"
4) "alfred"
5) "bertrand"

Now let's add a new property to these objects:

> set order:albert 5
> set order:alfred 3
> set order:casimir 1
> set order:joseph 4
> set order:bertrand 2

You can sort by the new order property:

> sort myset by order:*
1) "casimir"
2) "bertrand"
3) "alfred"
4) "joseph"
5) "albert"

Now if you need to sort by score AND this order property, then you have no other choice than materialize the order property in the zset OR materialize the score in the order property.

For instance, adding the order property in the zset, we get:

> del myset
> zadd myset 1 5:albert
> zadd myset 1 4:joseph
> zadd myset 4 2:bertrand
> zadd myset 2 1:casimir
> zadd myset 3 3:alfred
> zrange myset 0 -1
1) "4:joseph"
2) "5:albert"
3) "1:casimir"
4) "3:alfred"
5) "2:bertrand"

Beware: in that case, the property field is sorted according to the lexicographic order, so the value may have to be normalized if you need numerical order and multiple digits. There are various tricks to do this. For instance, instead of storing "1", "12" or "123", you can store "11", "212" or "3123", the first digit representing the number of digits of your number.

If both the score and the order property can change, this is not very convenient and you will be better served by sorting on client side. This can be achieved in two roundtrips by retrieving the zset with scores on one side, and the corresponding order values on the other side.

> zrange myset 0 -1 withscores
> sort myset by order:* get order:* get #

Up to the client to join the two results (using some kind of dictionary or associative array), and sort to get the final result.