I have a sorted set in Redis with timestamp and different type of relationships to the set is stored together.
Example dataset is explained below:
zadd s1 10 rel1:val1
zadd s1 15 rel1:val2
zadd s1 12 rel1:val3
zadd s1 10 rel2:v1
zadd s1 12 rel2:v2
zadd s1 5 rel1:v3
What I’m looking for top element of rel1 or rel2 from the set, if I tried to store them separately I will end with many keys, which I want to avoid.
I tried ZSCAN and the results are in asc order by score like below
localhost:6379> zscan s1 0 match "rel1*" count 10
1) "0"
2) 1) "rel1:v3"
2) "5"
3) "rel1:val1"
4) "10"
5) "rel1:val3"
6) "12"
7) "rel1:val2"
8) "15"
And if I score the timestamp in -ive I get the results as expected top element
localhost:6379> zadd s1 -10 rel1:val1
(integer) 0
localhost:6379> zadd s1 -20 rel1:val2
(integer) 0
localhost:6379> zadd s1 -30 rel1:val3
(integer) 0
localhost:6379> zscan s1 0 match "rel1*" count 10
1) "0"
2) 1) "rel1:val3"
2) "-30"
3) "rel1:val2"
4) "-20"
5) "rel1:val1"
6) "-10"
7) "rel1:v3"
8) "5"
My question can I relay on this results and believe the results are always in asc order with ZSCAN.
I can’t use ZREVRANGE or ZRANGE commands as I have to get top n items with MATCHING the members.
2
Answers
NO. You cannot rely on it. The order is undefined.
As we known, ZSET is implemented with a dict/hash, and a skiplist. ZSCAN command scans the dict, not the skiplist. Since dict is unordered, the order of scan result is undefined.
If you use small sample data like the given one, you might probably get the correctly ordered results. But don’t trust it.
Just as @for_stack said, ZSCAN doesn’t keep the order of results. You could generate a large number of samples to test it, then you will find. You have to switch to ZRANGE, ZREVRANGE or other ways.