すべてのプロダクト
Search
ドキュメントセンター

Tair (Redis® OSS-Compatible):exZset を使用して分散型リーダーボードを実装する

最終更新日:Nov 09, 2025

TairJedis クライアントを使用すると、exZset データ構造を使用して分散型リーダーボードを実装できます。単一のキーを操作するだけで済みます。Tair は、データと計算タスクを複数のサブキーに自動的に分散します。デフォルトでは 10 個のサブキーが使用され、その詳細を管理する必要はありません。このソリューションは、100,000 人を超えるメンバーを持つリーダーボードを簡単に作成し、large キーやホットキーを回避するのに役立ちます。

背景情報

分散型リーダーボードを実装するには、正確なランキングメソッドと不正確なランキングメソッド (線形補間) の 2 つのソリューションがあります。

表 1. 分散型リーダーボードを実装するためのソリューション

ソリューション

説明

正確なランキング (推奨)

データを計算のために異なるキーに分散します。クエリを実行するときは、各キーでターゲットデータのランクを見つけ、そのランクを合計します。

たとえば、3 つの基になるキーを使用するとします。リーダーボードを作成して 3,000 人のメンバーを挿入すると、Tair はこれらのメンバーを 3 つのサブリーダーボードに分散します。メンバー x のランクを見つけるには、FindRank(x) 操作で 3 つのサブリーダーボードにクエリを実行します。返されたランクが 124、183、156 の場合、メンバー x の実際のランクは 463 (124 + 183 + 156) です。

  • 利点: ランクが正確です。

  • 欠点: ランクを取得するための 時間計算量 は m × O(log(N)) です。

線形補間 (exZset では未実装)

このメソッドは、データをセグメントに分割します。各セグメントのメンバー数と最高ランクを記録します。セグメントの最小値と最大値の間にあるスコアについては、線形補間を使用してランクを推定します。

  • 利点: ランクの取得は比較的速く、時間計算量は O(m) です。

  • 欠点: ランクは推定値であり、誤差が生じる可能性があります。

このソリューションは、正確なランキングメソッドを使用して分散型リーダーボードを実装します。このソリューションで使用される exZset コマンドの詳細については、「exZset」をご参照ください。

コード例

このソリューションには、Tair によって開発された TairJedis クライアントが必要です。

  1. pom.xml 構成を追加します。

            <dependency>
                <groupId>com.aliyun.tair</groupId>
                <artifactId>alibabacloud-tairjedis-sdk</artifactId>
                <version>5.3.1</version>
            </dependency>
  2. サンプルコード。

    import io.valkey.JedisPool;
    import io.valkey.JedisPoolConfig;
    import com.aliyun.tair.tairzset.*;
    
    public class DistributedLeaderBoardExample {
        // インスタンスのエンドポイント、ポート、パスワード、およびその他の情報を構成します。
        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();
    
        // 分散型リーダーボードを構成します。
        private static final int shardKeySize = 10;  // 基になるサブリーダーボードの数。
        private static final int pageSize = 10;      // リーダーボードの各ページのメンバー数。
        private static final boolean reverse = true; // この例では、メンバーは降順でソートされます。
        private static final boolean useZeroIndexForRank = false; // この例では、ランクは 1 から始まります。
    
        public static void main(String[] args) {
            JedisPool jedisPool = new JedisPool(config, HOST, PORT, DEFAULT_CONNECTION_TIMEOUT,
                    DEFAULT_SO_TIMEOUT, PASSWORD, 0, null);
                    
            // 分散型リーダーボードを作成します。この例では、キーの名前は distributed_leaderboard です。
            DistributedLeaderBoard dlb = new DistributedLeaderBoard("distributed_leaderboard", jedisPool,
                shardKeySize, pageSize, reverse, useZeroIndexForRank);
    
            // 金メダルの数が同じ場合は、銀メダルの数でソートします。銀メダルの数も同じ場合は、銅メダルの数でソートします。
            //                    金 銀 銅
            dlb.addMember("A",     32,  21, 16);
            dlb.addMember("D",     14,  4,  16);
            dlb.addMember("C",     20,  7,  12);
            dlb.addMember("B",     25,  29, 21);
            dlb.addMember("E",     13,  21, 18);
            dlb.addMember("F",     13,  17,  14);
    
            // A のランクを取得します。
            dlb.rankFor("A"); // 1
            System.out.println(dlb.rankFor("A"));
    
            // 上位 3 件を取得します。
            dlb.top(3);
            System.out.println(dlb.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}]
        }
    }

    パラメーター:

    パラメーター

    タイプ

    説明

    shardKeySize

    int

    基になるサブリーダーボードの数。デフォルト値は 10 です。この数は動的にスケールアウトできません。サービスの初期段階でこの数を計画してください。

    pageSize

    int

    リーダーボードの各ページのメンバー数。デフォルト値は 10 です。

    reverse

    boolean

    有効な値:

    • false (デフォルト): 昇順でソートします。

    • true: 降順でソートします。

    useZeroIndexForRank

    boolean

    有効な値:

    • true (デフォルト): ランクは 0 から始まります。

    • false: ランクは 1 から始まります。

    詳細については、「alibabacloud-tairjedis-sdkcom.aliyun.tair.tairzset.DistributedLeaderBoard クラス」をご参照ください。

付録: 従来のリーダーボードと分散型リーダーボードの比較

次の表は、従来のリーダーボードと分散型リーダーボードの基本機能の実装を比較したものです。

基本機能

従来のリーダーボード

分散型リーダーボード

実装

時間計算量

実装

時間計算量

メンバーの挿入

EXZADD を使用して要素を挿入します。

O(log(N))

crc(key) & m を使用してターゲットキーを計算し、EXZADD を使用して要素を挿入します。

O(log(N))

メンバーのスコアを更新

EXZINCRBY を使用してスコアを更新します。

O(log(N))

crc(key) & m を使用してターゲットキーを計算し、EXZINCRBY を使用してスコアを更新します。

O(log(N))

メンバーの削除

EXZREM を使用してメンバーを削除します。

O(M*log(N))

crc(key) & m を使用してターゲットキーを計算し、EXZREM を使用してメンバーを削除します。

O(log(N))

メンバー数のクエリ

EXZCARD を使用してメンバー数をクエリします。

O(1)

EXZCARD を使用して各サブキーのメンバー数をクエリし、その結果を合計します。

O(m)

説明

この列では、m はシャードの数を示します。

総ページ数のクエリ

EXZCARD を使用してメンバー数をクエリし、その結果を PAGE_SIZE (ページあたりのレコード数) で割ります。

O(1)

EXZCARD を使用して各サブキーのメンバー数をクエリし、結果を合計してから、合計を PAGE_SIZE (ページあたりのレコード数) で割ります。

O(m)

スコア範囲内のメンバーの総数

EXZCOUNT を使用してクエリします。

O(log(N))

各サブキーで EXZCOUNT を実行し、結果をマージします。

m × O(log(N))

スコア範囲内のメンバーを削除

EXZREMRANGEBYSCORE を使用してメンバーを削除します。

O(log(N)+M)

各サブキーで EXZREMRANGEBYSCORE を実行します。

m × O(log(N))

メンバーのスコアを取得

EXZSCORE を使用してクエリします。

O(1)

crc(key) & m を使用してターゲットキーを計算し、EXZSCORE を実行します。

O(1)

メンバーのランクを取得

EXZRANK を使用してクエリします。

O(log(N))

各サブキーで EXZRANKBYSCORE を呼び出し、その結果を合計します。

m × O(log(N))

メンバーのスコアとランクを同時に取得

EXZSCORE と EXZRANK を使用してクエリします。

O(log(N))

  1. crc(key) & m を使用してターゲットキーを計算し、EXZSCORE を実行します。

  2. 各サブキーで EXZRANKBYSCORE を呼び出し、その結果を合計します。

m × O(log(N))

上位 i 番目のメンバーをクエリ

EXZRANGE を使用してクエリします。

O(log(N)+M)

EXZRANGE を使用して各サブキーから上位 i 人のメンバーをクエリし、結果をマージして最終的な上位 i 人のメンバーを見つけます。

m × O(log(N))

リーダーボードの i ページ目を取得

EXZRANGE を使用してクエリします。

O(log(N))

各サブキーからターゲットページより前のすべてのメンバーを取得し、それらをソートして最終ページを取得します。

m × O(log(N))

有効期限の設定

EXPIRE を使用して時間を設定します。

O(1)

各サブキーに有効期限を設定します。

O(m)

リーダーボードの削除

DEL を使用して削除します。

O(N)

各サブキーを削除します。

m × O(N)