Os conjuntos ordenados nativos do Redis classificam membros por uma única pontuação, o que dificulta a implementação de tabelas de medalhas, rankings por janela de tempo e outros leaderboards multidimensionais sem soluções alternativas. O exZset (também chamado TairZset) ordena pontuações do tipo double em até 256 dimensões, eliminando a necessidade de concatenação complexa de pontuações e permitindo incrementos atômicos em todas as dimensões.
Use o exZset quando precisar:
Classificar participantes por vários critérios simultaneamente (por exemplo, contagem de medalhas de ouro, prata e bronze)
Consultar leaderboards em diferentes janelas de tempo — horária, diária, semanal ou mensal — a partir de uma única chave
Dimensionar cargas de trabalho de leaderboard para shards adicionais quando o armazenamento ou a computação estiverem limitados
Para obter a referência completa de comandos, consulte comandos exZset.
Por que usar exZset em vez do Zset nativo
O Conjunto Ordenado nativo do Redis (Zset) suporta classificação por uma única pontuação do tipo double. Uma solução alternativa comum é concatenar pontuações usando o padrão IEEE 754, mas essa abordagem apresenta três desvantagens: implementação complexa, precisão reduzida e impossibilidade de usar o comando ZINCRBY.
O exZset resolve todos esses problemas:
|
Recurso |
Zset nativo |
Solução alternativa IEEE 754 |
exZset |
|
Dimensões de classificação |
1 |
Múltiplas (com perda de precisão) |
Até 256 |
|
Incremento atômico |
|
Não suportado |
|
|
Compatibilidade de API |
— |
— |
Semelhante ao Zset nativo |
|
Leaderboards distribuídos |
Não |
Não |
Sim |
|
Cliente Java |
— |
— |
Open source TairJedis |
Como as pontuações são comparadas
O exZset usa # como separador de dimensões e compara as pontuações da esquerda para a direita: avalia primeiro a dimensão mais à esquerda e só avança para a direita quando os valores são iguais. Se todas as dimensões forem idênticas, os membros são classificados pela ordem ASCII.
Para uma pontuação score1#score2#score3:
Compare
score1. Se houver diferença, isso define a classificação.Se
score1for igual, comparescore2. Valores distintos determinam o ranking.Se
score2também for igual, comparescore3.
Considere # como um ponto decimal: 0#99 < 99#90 < 99#99 — a dimensão mais à esquerda sempre tem prioridade.
Crie uma tabela de medalhas
Uma tabela de medalhas classifica os participantes primeiramente pelo ouro, depois pela prata e, por fim, pelo bronze. Com o exZset, codifique a contagem de medalhas de cada participante como uma pontuação tridimensional (gold#silver#bronze). Assim, a lógica de classificação fica incorporada na própria estrutura de dados, sem necessidade de ordenação no nível da aplicação.
Dados de exemplo:
|
Classificação |
Participante |
** |
** |
** |
|
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 |
Os participantes E e F possuem ambos 13 medalhas de ouro. E ocupa uma posição superior porque tem 21 medalhas de prata contra 17 de F.
Pré-requisitos
Antes de começar, verifique se você tem:
Endpoint, porta e senha de uma instância Tair
SDK TairJedis adicionado ao seu projeto
Adicionar a dependência do TairJedis
Adicione o seguinte trecho ao arquivo pom.xml:
<dependency>
<groupId>com.aliyun.tair</groupId>
<artifactId>alibabacloud-tairjedis-sdk</artifactId>
<version>5.3.1</version>
</dependency>
Inserir e consultar dados do leaderboard
O exemplo abaixo usa a classe LeaderBoard do SDK TairJedis. O construtor recebe o nome da chave, o pool de conexões, o tamanho da página e as opções de ordenação.
import io.valkey.JedisPool;
import io.valkey.JedisPoolConfig;
import com.aliyun.tair.tairzset.LeaderBoard;
public class LeaderBoardExample {
// Replace with your instance endpoint and credentials.
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 named "leaderboard".
LeaderBoard lb = new LeaderBoard("leaderboard", jedisPool, 10, true, false);
// Add members with three-dimensional scores: gold, silver, bronze.
lb.addMember("A", 32, 21, 16);
lb.addMember("B", 25, 29, 21);
lb.addMember("C", 20, 7, 12);
lb.addMember("D", 14, 4, 16);
lb.addMember("E", 13, 21, 18);
lb.addMember("F", 13, 17, 14);
// Get the rank of A (1-indexed).
System.out.println(lb.rankFor("A"));
// 1
// Get the 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 full leaderboard.
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}]
}
}
Para ver todos os métodos disponíveis da classe LeaderBoard, consulte o Javadoc do alibabacloud-tairjedis-sdk em com.aliyun.tair.tairzset.LeaderBoard.
Os exemplos acima usam Java com TairJedis. Para outras linguagens, chame diretamente os comandos exZset — veja comandos exZset.
Crie leaderboards por janela de tempo
É possível fornecer leaderboards horários, diários, semanais e mensais a partir de uma única chave codificando o tempo tanto na pontuação quanto no nome do membro. Essa estratégia aproveita a comparação da esquerda para a direita do exZset para filtrar entradas por intervalo de tempo usando EXZREVRANGEBYSCORE.
Design de chave e pontuação
Armazene todos os dados de um mês em uma única chave (por exemplo, julyZset). Cada entrada codifica o tempo em seis dimensões:
score format: month#week#day#hour#minute#points
member format: month#week#day#hour#minute_username
|
Dimensão |
Valor de exemplo |
Significado |
|
|
|
Julho |
|
|
|
Segunda semana do mês |
|
|
|
6º dia da semana |
|
|
|
16:00 |
|
|
|
:22 |
|
|
|
Pontuação obtida naquele momento |
O prefixo de tempo no nome do membro vincula cada entrada a um minuto específico. Como o exZset compara as dimensões da esquerda para a direita, defina as dimensões inferiores como 0 no comando EXZREVRANGEBYSCORE cria um limite inferior inclusivo para qualquer granularidade de tempo — as dimensões mais à esquerda funcionam como filtro principal.
Inserir dados com EXZINCRBY
Use EXZINCRBY para adicionar ou incrementar a pontuação de um membro atomicamente, sem ciclo de leitura-modificação-escrita.
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
Consultar leaderboards por janela de tempo
Todas as consultas de intervalo usam EXZREVRANGEBYSCORE com limites de pontuação correspondentes à janela de tempo desejada.
|
Leaderboard |
Intervalo de pontuação |
Comando |
Saída |
|
Horário em tempo real (15:23–16:23, hora atual 16:23) |
Todas as entradas atualizadas nos últimos 60 minutos |
|
|
|
Hora específica (16:00–17:00) |
Todas as entradas na janela 16:xx |
|
|
|
Diário (5 de julho) |
Todas as entradas no dia 5 da semana 2 |
|
|
|
Semanal (semana 2 de julho) |
Todas as entradas na semana 2 |
|
|
|
Mensal (julho) |
Todas as entradas em julho |
|
|
Para rankings acessados frequentemente, como o leaderboard horário em tempo real, armazene os resultados em cache para reduzir consultas repetidas de intervalo.
Próximos passos
Comandos exZset — referência completa de comandos para exZset
alibabacloud-tairjedis-sdk — código-fonte do SDK TairJedis e exemplos adicionais