DEV Community

Cover image for StackExchange.Redis: Usando estruturas de dados Redis Sets
Paulo Walraven
Paulo Walraven

Posted on

StackExchange.Redis: Usando estruturas de dados Redis Sets

Introdução

Redis Sets são uma implementação de um conjunto matemático. E tem as seguintes características:

  • Eles são desordenados.
  • Eles não permitem duplicação, portanto não há membros repetidos.
  • Eles podem ser combinados para criar novos conjuntos.

Redis Sets na prática

Imaginemos que estejamos criando um MMORPG e temos esses 5 conjuntos de usuários

  • ActiveUsers
  • InactiveUsers
  • OnlineUsers
  • OfflineUsers
  • AllUsers

Agora vamos preencher nossos conjuntos de usuários ativos, inativos e offline. Para fazer isso, usaremos o método SetAddAsync. Este método é variável, então podemos fazer isso em um comando para cada conjunto.

var activeUsers = new string[] { "User:1", "User:2" };
var inactiveUsers = new string[] { "User:3", "User:4" };
var offlineUsers = new string[] { "User:5", "User:6", "User:7" };
await database.SetAddAsync(activeUsersKey, activeUsers.Select(u => (RedisValue)u).ToArray());
await database.SetAddAsync(inactiveUsersKey, inactiveUsers.Select(u => (RedisValue)u).ToArray());
await database.SetAddAsync(offlineUsersKey, offlineUsers.Select(u => (RedisValue)u).ToArray());
Enter fullscreen mode Exit fullscreen mode

Combinando conjuntos para obter todos os usuários

Não preenchemos nosso conjunto allUsersKey. Se considerarmos active, inactive, offline, podemos usar as operações de combinação de conjuntos para obter um conjunto com todos os nossos usuários.

await database.SetCombineAndStoreAsync(SetOperation.Union, allUsersKey, new RedisKey[] { activeUsersKey, inactiveUsersKey, offlineUsersKey });
Enter fullscreen mode Exit fullscreen mode

Verificar associação

Os conjuntos não permitem a duplicação, mas permitem verificações de associação O(1) muito rápidas. Portanto, se quiséssemos verificar se User:6 está offline, poderíamos fazê-lo facilmente:

var user6Offline = await database.SetContainsAsync(offlineUsersKey, "User:6");
Console.WriteLine($"User:6 offline: {user6Offline}");
Enter fullscreen mode Exit fullscreen mode
// output 
User:6 offline: True
Enter fullscreen mode Exit fullscreen mode

Enumerar Conjunto

Quando você deseja enumerar os membros de um conjunto, tem duas opções: pode enumerar todos de uma vez ou pode examinar o conjunto e enumerar tudo.

Enumerar todo o conjunto

Se você quiser garantir que está enumerando todo o conjunto em uma viagem de ida e volta, poderá fazê-lo usando o método SetMembersAsync. Isso usará o comando SMEMBERS no Redis. Se o seu conjunto for relativamente compacto (abaixo de 1.000 membros), essa é uma maneira perfeitamente válida de retirar todos os membros do conjunto.

Console.WriteLine($"All Users In one shot: {string.Join(", ", await database.SetMembersAsync(allUsersKey))}");
Enter fullscreen mode Exit fullscreen mode
// output
All Users In one shot: User:3, User:1, User:4, User:6, User:7, User:2, User:5
Enter fullscreen mode Exit fullscreen mode

Enumerar Conjunto em Blocos

A maneira alternativa de enumerar um conjunto é enumerar com SetScanAsync, que criará um Set Enumerator e usará o comando SSCAN para varrer todo o conjunto até que o conjunto se esgote.

Console.Write("All Users with scan: ");
await foreach (var user in database.SetScanAsync(allUsersKey))
{
    Console.Write($"{user}, ");
}
Enter fullscreen mode Exit fullscreen mode
// output
All Users with scan: User:1, User:2, User:3, User:6, User:7, User:5, User:4,
Enter fullscreen mode Exit fullscreen mode

Mover elementos entre conjuntos

ma operação muito normal que você pode precisar executar com conjuntos é mover elementos entre eles. Por exemplo, se User:1 fosse mover offline, você pode usar SetMoveAsyncpara movê-los do conjunto de usuários ativos para o conjunto de usuários offline.

Console.WriteLine($"Moving User:1 from active to offline");
var moved = await database.SetMoveAsync(activeUsersKey, offlineUsersKey, "User:1");
Console.WriteLine($"Move successful: {moved}");
Enter fullscreen mode Exit fullscreen mode
// output
Move successful: True
Enter fullscreen mode Exit fullscreen mode

Conclusão

O Redis Sets é uma implementação de um conjunto matemático com recursos avançados. Eles são desordenados, não permitem duplicação e permitem a combinação de conjuntos para criar novos conjuntos. A combinação de conjuntos é uma funcionalidade que permite a criação de novos conjuntos por meio da união, interseção ou diferença entre conjuntos. Os conjuntos Redis são particularmente úteis para operações que exigem associação O(1), como verificar se um elemento pertence a um conjunto, e também para a manipulação de membros de conjuntos comuns, como adicionar ou remover um membro. O Redis Sets fornece muitas outras operações úteis, como enumerar conjuntos em blocos e mover elementos entre conjuntos. Em resumo, o Redis Sets é uma ferramenta poderosa e flexível para lidar com conjuntos de dados e é amplamente utilizado em muitas aplicações.

Código completo

using StackExchange.Redis;
using System.Diagnostics;

var options = new ConfigurationOptions
{
    EndPoints = new EndPointCollection { "localhost:6379" }
};

var conn = ConnectionMultiplexer.Connect(options);
var database = conn.GetDatabase();

var allUsersKey = "users";
var activeUsersKey = "users:state:active";
var inactiveUsersKey = "users:state:inactive";
var offlineUsersKey = "users:state:offline";
await database.KeyDeleteAsync(new RedisKey[] { allUsersKey, activeUsersKey, inactiveUsersKey, offlineUsersKey });

var activeUsers = new string[] { "User:1", "User:2" };
var inactiveUsers = new string[] { "User:3", "User:4" };
var offlineUsers = new string[] { "User:5", "User:6", "User:7" };
await database.SetAddAsync(activeUsersKey, activeUsers.Select(u => (RedisValue)u).ToArray());
await database.SetAddAsync(inactiveUsersKey, inactiveUsers.Select(u => (RedisValue)u).ToArray());
await database.SetAddAsync(offlineUsersKey, offlineUsers.Select(u => (RedisValue)u).ToArray());

await database.SetCombineAndStoreAsync(SetOperation.Union, allUsersKey, new RedisKey[] { activeUsersKey, inactiveUsersKey, offlineUsersKey });

var user6Offline = await database.SetContainsAsync(offlineUsersKey, "User:6");
Console.WriteLine($"User:6 offline: {user6Offline}");

Console.WriteLine($"All Users In one shot: {string.Join(", ", await database.SetMembersAsync(allUsersKey))}");

Console.Write("All Users with scan: ");
await foreach (var user in database.SetScanAsync(allUsersKey))
{
    Console.Write($"{user}, ");
}

Console.WriteLine($"Moving User:1 from active to offline");
var moved = await database.SetMoveAsync(activeUsersKey, offlineUsersKey, "User:1");
Console.WriteLine($"Move successful: {moved}");
Enter fullscreen mode Exit fullscreen mode

Latest comments (0)