All Products
Search
Document Center

Tair (Redis® OSS-Compatible):Implement multidimensional leaderboards using exZset

Last Updated:Aug 19, 2025

exZset is a data structure developed by Alibaba Cloud that can sort double-type scores across up to 256 dimensions.

Background information

The native Redis Sorted Set (Zset) data structure supports sorting based on a double-type score in only one dimension, which makes it difficult to implement multidimensional sorting. For example, you can use the IEEE 754 standard to concatenate score data for multidimensional sorting. However, this method has several limitations, such as a complex implementation, reduced precision, and the inability to use the ZINCRBY command.

Features of exZset

The exZset data structure, developed by Alibaba Cloud, helps you easily implement multidimensional sorting and has the following advantages over traditional solutions:

  • Supports sorting of double-type scores across a maximum of 256 dimensions. The sorting priority is from left to right.

    For a multidimensional score, the score on the left has a higher priority than the score on the right. For example, consider a three-dimensional score: score1#score2#score3. When exZset compares scores, it first compares score1. It compares score2 only if the score1 values are equal. Otherwise, the comparison result of score1 is the final comparison result for the entire score. Similarly, it compares score3 only if the score2 values are equal. If all dimensional scores are identical, the elements are sorted by their ASCII order.

    To make this easier to understand, you can imagine the hash symbol (#) as a decimal point (.). For example, the relationship between 0#99, 99#90, and 99#99 can be understood as 0.99 < 99.90 < 99.99. This means 0#99 < 99#90 < 99#99.

  • Supports the EXZINCRBY command. You no longer need to retrieve the current data, add a value locally, and then write the concatenated result back to Tair.

  • Provides APIs similar to those of native Zset.

  • Provides capabilities for both standard leaderboards and distributed architecture leaderboards .

  • Provides an open source TairJedis client. No encoding or decoding encapsulation is required. You can also refer to the open source code to implement encapsulation in other languages.

Note

For more information about the exZset commands that are mentioned in this topic, see exZset.

Scenarios

Sorting is a common requirement for leaderboards in games, applications, and medal tables. Common business requirements for sorting include the following:

  • Support for create, read, update, delete (CRUD) operations, reverse sorting, and member query based on the specified score range.

  • Quick retrieval of sorting results.

  • Scalability to implement distributed leaderboards Workloads can be offloaded to other data shards when the current data shard has insufficient storage or computing power.

Implement a medal table

In a medal leaderboard, participants are ranked based on the number of gold, silver, and bronze medals. They are first sorted by the number of gold medals. If the number of gold medals is the same, they are sorted by the number of silver medals. If the number of silver medals is also the same, they are sorted by the number of bronze medals. In this example, Participants E and F have the same number of gold medals, but Participant E has more silver medals than Participant F. Therefore, Participant E ranks higher. With the multidimensional sorting capability of exZset, you can meet this requirement using simple APIs.

Rank

Participant

金牌Gold medal

银牌Silver medal

铜牌Bronze medal

1

A

32

21

16

2

B

25

29

21

3

C

20

7

12

4

D

14

4

16

5

E

13

21

18

6

F

13

17

14

Code example

This solution requires the TairJedis client, which is developed by Tair.

  1. Add the pom.xml configuration.

            <dependency>
                <groupId>com.aliyun.tair</groupId>
                <artifactId>alibabacloud-tairjedis-sdk</artifactId>
                <version>5.3.1</version>
            </dependency>
  2. Sample code.

    import io.valkey.JedisPool;
    import io.valkey.JedisPoolConfig;
    import com.aliyun.tair.tairzset.LeaderBoard;
    
    public class LeaderBoardExample {
        // Configure the instance endpoint, port number, password, and other information.
        private static final int DEFAULT_CONNECTION_TIMEOUT = 5000;
        private static final int DEFAULT_SO_TIMEOUT = 2000;
        private static final String HOST = "<r-bp1mx0ydsivrbp****.redis.rds.aliyuncs.com>";
        private static final int PORT = 6379;
        private static final String PASSWORD = "<Pass****word>";
        private static final JedisPoolConfig config = new JedisPoolConfig();
    
        public static void main(String[] args) {
            JedisPool jedisPool = new JedisPool(config, HOST, PORT, DEFAULT_CONNECTION_TIMEOUT,
                    DEFAULT_SO_TIMEOUT, PASSWORD, 0, null);
    
            // Create a leaderboard.
            LeaderBoard lb = new LeaderBoard("leaderboard", jedisPool, 10, true, false);
    
            // If the number of gold medals is the same, sort by the number of silver medals. If the number of silver medals is also the same, sort by the number of bronze medals.
            //                    Gold Silver Bronze
            lb.addMember("A",     32,  21, 16);
            lb.addMember("D",     14,  4,  16);
            lb.addMember("C",     20,  7,  12);
            lb.addMember("B",     25,  29, 21);
            lb.addMember("E",     13,  21, 18);
            lb.addMember("F",     13,  17,  14);
    
            // Get the rank of A.
            lb.rankFor("A"); // 1
            System.out.println(lb.rankFor("A"));
    
            // Get the top 3.
            lb.top(3);
            System.out.println(lb.top(3));
            // [{"member":"A","score":"32#21#16","rank":1}, 
            // {"member":"B","score":"25#29#21","rank":2}, 
            // {"member":"C","score":"20#7#12","rank":3}]
    
            // Get the entire leaderboard.
            lb.allLeaders();
            System.out.println(lb.allLeaders());
            // [{"member":"A","score":"32#21#16","rank":1}, 
            // {"member":"B","score":"25#29#21","rank":2}, 
            // {"member":"C","score":"20#7#12","rank":3}, 
            // {"member":"D","score":"14#4#16","rank":4}, 
            // {"member":"E","score":"13#21#18","rank":5}, 
            // {"member":"F","score":"13#17#14","rank":6}]
        }
    } 

    For more information about operations, see the com.aliyun.tair.tairzset.LeaderBoard section in the alibabacloud-tairjedis-sdk documentation.

Use TairZset to implement leaderboards by hour, day, week, or month or in real time

If you want to implement a monthly leaderboard for a key, the month information must be used as the index.

Leaderboards of various time ranges can be implemented using multi-level indexing provided by the TairZset data structure. In this example, all data of the month is stored in a key named julyZset. The following code shows how to write the sample data to the key:

EXZINCRBY julyZset 7#2#6#16#22#100 7#2#6#16#22_user1
EXZINCRBY julyZset 7#2#6#16#22#50 7#2#6#16#22_user2
EXZINCRBY julyZset 7#2#6#16#23#70 7#2#6#16#23_user1
EXZINCRBY julyZset 7#2#6#16#23#80 7#2#6#16#23_user1
Note
  • 7#2#6#16#22#100 indicates that the score was updated to 100 at 16:22 on the 6th day of the 2nd week of July.

  • 7#2#6#16#22_user1 indicates the user whose score was updated at this point in time. A time prefix is added to the username.

Leaderboard type

Command and output

Real-time hourly leaderboard. This type of leaderboards includes the members whose scores were updated within an hour before the current time. For example, if the current time is 16:23, the leaderboard includes the members whose scores were updated within the range of 15:23 to 16:23.

Note

If the ranking results are frequently accessed, we recommend that you cache the ranking results.

Command:

EXZREVRANGEBYSCORE julyZset 7#2#6#16#23#0 7#2#6#15#23#0

Output:

1) "7#2#6#16#22_user1"
2) "7#2#6#16#22_user2"

Leaderboard for a specific hour. For example, you can query the leaderboard that includes the members whose scores were updated within the time range of 16:00 to 17:00.

Command:

EXZREVRANGEBYSCORE julyZset 7#2#6#17#0#0 7#2#6#16#0#0

Output:

1) "7#2#6#16#22_user1"
2) "7#2#6#16#22_user2"

Daily leaderboard. For example, you can query the leaderboard whose data was generated on July 5.

Before the query, use the following command to insert a data record that was generated on July 5:

EXZINCRBY julyZset 7#2#5#10#23#70 7#2#5#10#23_user1

Output:

"7#2#5#10#23#70"

Command:

EXZREVRANGEBYSCORE julyZset 7#2#6#0#0#0 7#2#5#0#0#0

Output:

1) "7#2#5#10#23_user1"

Weekly leaderboard. For example, you can query the leaderboard for the second week of July.

Command:

EXZREVRANGEBYSCORE julyZset 7#3#0#0#0#0 7#2#0#0#0#0

Output:

1) "7#2#6#16#22_user1"
2) "7#2#6#16#22_user2"
3) "7#2#5#10#23_user1"

Monthly leaderboard. For example, you can query the leaderboard of July.

Before the query, use the following command to insert a data record that was generated on July 20:

EXZINCRBY julyZset 7#4#20#12#20#50 7#4#20#12#20_user1

Output:

"7#4#20#12#20#50"

Command:

EXZREVRANGEBYSCORE julyZset 7#6#0#0#0#0 7#0#0#0#0#0

Output:

1) "7#4#20#12#20_user1"
2) "7#2#6#16#22_user1"
3) "7#2#6#16#22_user2"
4) "7#2#5#10#23_user1"