Lorsqu'une seule clé de type sorted set contient des centaines de milliers de membres, elle devient une clé sensible (hot key) et une clé volumineuse (large key), ce qui dégrade les performances. Le client TairJedis fournit la classe DistributedLeaderBoard qui répartit de manière transparente les données du classement sur plusieurs sous-classements. Une clé logique est ventilée vers N sous-classements ; les requêtes de rang agrègent les résultats de tous les sous-classements et additionnent les rangs par sous-classement pour produire le rang final de chaque membre. Cela vous permet de créer des classements contenant plus de 100 000 membres sans avoir à gérer vous-même le partitionnement des données.
Fonctionnement du classement précis
exZset prend en charge deux méthodes de calcul des rangs dans un classement distribué : le classement précis (recommandé) et l'interpolation linéaire (non encore implémentée dans exZset).
Le classement précis répartit les membres sur N sous-classements à l'aide d'un hachage CRC (Cyclic Redundancy Check) de la clé de chaque membre. Pour obtenir le rang du membre x, FindRank(x) interroge chaque sous-classement et additionne les rangs renvoyés. Par exemple, avec trois sous-classements et 3 000 membres au total, si les rangs par sous-classement pour le membre x sont 124, 183 et 156, le rang final est 463. Les rangs sont exacts et la complexité temporelle pour récupérer un rang est m × O(log(N)), où m représente le nombre de sous-classements.
L'interpolation linéaire divise les données en segments de scores, enregistre le nombre de membres et le rang le plus élevé pour chaque segment, puis estime les rangs par interpolation. L'obtention d'un rang est de complexité O(m), mais les rangs sont approximatifs.
Utilisez le classement précis, sauf si votre cas d'utilisation peut tolérer des rangs estimés. Pour plus d'informations sur les commandes exZset utilisées dans cette rubrique, consultez les commandes exZset.
Prérequis
Avant de commencer, assurez-vous de disposer des éléments suivants :
Un endpoint, un port et un mot de passe pour l'instance Tair
Un environnement de développement Java avec Maven
Configurer le classement
Étape 1 : Ajouter la dépendance Maven
Ajoutez les lignes suivantes à votre fichier pom.xml :
<dependency>
<groupId>com.aliyun.tair</groupId>
<artifactId>alibabacloud-tairjedis-sdk</artifactId>
<version>5.3.1</version>
</dependency>
Étape 2 : Configurer et exécuter le classement
L'exemple suivant crée un classement distribué, ajoute six membres avec des scores multidimensionnels (nombre de médailles d'or, d'argent et de bronze), puis récupère le rang d'un membre ainsi que le top 3 global.
import io.valkey.JedisPool;
import io.valkey.JedisPoolConfig;
import com.aliyun.tair.tairzset.*;
public class DistributedLeaderBoardExample {
// Instance connection settings
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();
// Leaderboard settings
private static final int shardKeySize = 10; // Number of sub-leaderboards
private static final int pageSize = 10; // Members per page
private static final boolean reverse = true; // true = descending order (highest score first)
private static final boolean useZeroIndexForRank = false; // false = ranks start from 1
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool(config, HOST, PORT, DEFAULT_CONNECTION_TIMEOUT,
DEFAULT_SO_TIMEOUT, PASSWORD, 0, null);
// Create the distributed leaderboard
DistributedLeaderBoard dlb = new DistributedLeaderBoard("distributed_leaderboard", jedisPool,
shardKeySize, pageSize, reverse, useZeroIndexForRank);
// Add members with multi-dimensional scores: gold, silver, bronze
// Members are sorted by gold first, then silver, then bronze
dlb.addMember("A", 32, 21, 16);
dlb.addMember("B", 25, 29, 21);
dlb.addMember("C", 20, 7, 12);
dlb.addMember("D", 14, 4, 16);
dlb.addMember("E", 13, 21, 18);
dlb.addMember("F", 13, 17, 14);
// Get the rank of member A
System.out.println(dlb.rankFor("A")); // 1
// Get the top 3 members
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}]
}
}
Remplacez les espaces réservés suivants par vos valeurs réelles :
| Espace réservé | Description | Exemple |
|---|---|---|
<r-bp1mx0ydsivrbp****.redis.rds.aliyuncs.com> |
Endpoint de l'instance | r-bp1example.redis.rds.aliyuncs.com |
<Pass****word> |
Mot de passe de l'instance | Votre mot de passe d'instance |
Le champ score dans la réponse top() encode les valeurs multidimensionnelles séparées par #. Pour le membre A, "score":"32#21#16" signifie 32 médailles d'or, 21 d'argent et 16 de bronze.
Paramètres
| Paramètre | Type | Description | Valeur par défaut |
|---|---|---|---|
shardKeySize |
int | Nombre de sous-classements. Planifiez cette valeur dès le départ, car elle ne peut pas être augmentée dynamiquement après la création du classement. | 10 |
pageSize |
int | Nombre de membres par page. | 10 |
reverse |
boolean | Ordre de tri. true trie par ordre décroissant (score le plus élevé en premier). false trie par ordre croissant. |
false |
useZeroIndexForRank |
boolean | Indexation des rangs. true commence les rangs à 0. false commence les rangs à 1. |
true |
Pour la liste complète des méthodes disponibles, consultez la classe com.aliyun.tair.tairzset.DistributedLeaderBoard dans la Javadoc alibabacloud-tairjedis-sdk.
Annexe : Classements conventionnels vs distribués
Le tableau suivant compare la complexité temporelle des opérations courantes entre un classement conventionnel (une seule clé exZset) et un classement distribué (m sous-classements).
Dans la colonne « Distribué », m représente le nombre de sous-classements et N le nombre de membres dans un sous-classement.
| Opération | Classement conventionnel | Classement distribué | ||
|---|---|---|---|---|
| Implémentation conventionnelle | Complexité conventionnelle | Implémentation distribuée | Complexité distribuée | |
| Insérer un membre | EXZADD |
O(log(N)) | Calculer le sous-classement cible avec crc(key) & m, puis EXZADD |
O(log(N)) |
| Mettre à jour le score d'un membre | EXZINCRBY |
O(log(N)) | Calculer le sous-classement cible avec crc(key) & m, puis EXZINCRBY |
O(log(N)) |
| Supprimer un membre | EXZREM |
O(M\*log(N)) | Calculer le sous-classement cible avec crc(key) & m, puis EXZREM |
O(log(N)) |
| Compter tous les membres | EXZCARD |
O(1) | EXZCARD sur chaque sous-classement, puis somme |
O(m) |
| Compter le nombre total de pages | EXZCARD ÷ taille de page |
O(1) | EXZCARD sur chaque sous-classement, somme, puis division par la taille de page |
O(m) |
| Compter les membres dans une plage de scores | EXZCOUNT |
O(log(N)) | EXZCOUNT sur chaque sous-classement, puis fusion |
m × O(log(N)) |
| Supprimer les membres dans une plage de scores | EXZREMRANGEBYSCORE |
O(log(N)+M) | EXZREMRANGEBYSCORE sur chaque sous-classement |
m × O(log(N)) |
| Obtenir le score d'un membre | EXZSCORE |
O(1) | Calculer le sous-classement cible avec crc(key) & m, puis EXZSCORE |
O(1) |
| Obtenir le rang d'un membre | EXZRANK |
O(log(N)) | EXZRANKBYSCORE sur chaque sous-classement, puis somme |
m × O(log(N)) |
| Obtenir le score et le rang d'un membre | EXZSCORE + EXZRANK |
O(log(N)) | 1. Calculer le sous-classement cible avec crc(key) & m, puis EXZSCORE. 2. EXZRANKBYSCORE sur chaque sous-classement, puis somme. |
m × O(log(N)) |
| Obtenir les i premiers membres | EXZRANGE |
O(log(N)+M) | EXZRANGE des i premiers de chaque sous-classement, puis fusion |
m × O(log(N)) |
| Obtenir la page i du classement | EXZRANGE |
O(log(N)) | Récupérer tous les membres précédant la page cible de chaque sous-classement, puis trier | m × O(log(N)) |
| Définir une durée d'expiration | EXPIRE |
O(1) | EXPIRE sur chaque sous-classement |
O(m) |
| Supprimer le classement | DEL |
O(N) | DEL sur chaque sous-classement |
m × O(N) |