Redis
 sql >> Base de données >  >> NoSQL >> Redis

Premiers pas avec les API client Redis

Vous trouverez ci-dessous un exemple simple pour vous donner une idée de la facilité d'utilisation de certaines des structures de données avancées de Redis - dans ce cas, les listes Redis :Le code source complet de cet exemple est visible en ligne

using var redisClient = new RedisClient();
//Create a 'strongly-typed' API that makes all Redis Value operations to apply against Shippers
IRedisTypedClient<Shipper> redis = redisClient.As<Shipper>();

//Redis lists implement IList<T> while Redis sets implement ICollection<T>
var currentShippers = redis.Lists["urn:shippers:current"];
var prospectiveShippers = redis.Lists["urn:shippers:prospective"];

currentShippers.Add(
    new Shipper {
        Id = redis.GetNextSequence(),
        CompanyName = "Trains R Us",
        DateCreated = DateTime.UtcNow,
        ShipperType = ShipperType.Trains,
        UniqueRef = Guid.NewGuid()
    });

currentShippers.Add(
    new Shipper {
        Id = redis.GetNextSequence(),
        CompanyName = "Planes R Us",
        DateCreated = DateTime.UtcNow,
        ShipperType = ShipperType.Planes,
        UniqueRef = Guid.NewGuid()
    });

var lameShipper = new Shipper {
    Id = redis.GetNextSequence(),
    CompanyName = "We do everything!",
    DateCreated = DateTime.UtcNow,
    ShipperType = ShipperType.All,
    UniqueRef = Guid.NewGuid()
};

currentShippers.Add(lameShipper);

Dump("ADDED 3 SHIPPERS:", currentShippers);

currentShippers.Remove(lameShipper);

Dump("REMOVED 1:", currentShippers);

prospectiveShippers.Add(
    new Shipper {
        Id = redis.GetNextSequence(),
        CompanyName = "Trucks R Us",
        DateCreated = DateTime.UtcNow,
        ShipperType = ShipperType.Automobiles,
        UniqueRef = Guid.NewGuid()
    });

Dump("ADDED A PROSPECTIVE SHIPPER:", prospectiveShippers);

redis.PopAndPushBetweenLists(prospectiveShippers, currentShippers);

Dump("CURRENT SHIPPERS AFTER POP n' PUSH:", currentShippers);
Dump("PROSPECTIVE SHIPPERS AFTER POP n' PUSH:", prospectiveShippers);

var poppedShipper = redis.PopFromList(currentShippers);
Dump("POPPED a SHIPPER:", poppedShipper);
Dump("CURRENT SHIPPERS AFTER POP:", currentShippers);

//reset sequence and delete all lists
redis.SetSequence(0);
redis.Remove(currentShippers, prospectiveShippers);
Dump("DELETING CURRENT AND PROSPECTIVE SHIPPERS:", currentShippers);

EXEMPLE DE SORTIE :

ADDED 3 SHIPPERS:
Id:1,CompanyName:Trains R Us,ShipperType:Trains,DateCreated:2010-01-31T11:53:37.7169323Z,UniqueRef:d17c5db0415b44b2ac5da7b6ebd780f5
Id:2,CompanyName:Planes R Us,ShipperType:Planes,DateCreated:2010-01-31T11:53:37.799937Z,UniqueRef:e02a73191f4b4e7a9c44eef5b5965d06
Id:3,CompanyName:We do everything!,ShipperType:All,DateCreated:2010-01-31T11:53:37.8009371Z,UniqueRef:d0c249bbbaf84da39fc4afde1b34e332

REMOVED 1:
Id:1,CompanyName:Trains R Us,ShipperType:Trains,DateCreated:2010-01-31T11:53:37.7169323Z,UniqueRef:d17c5db0415b44b2ac5da7b6ebd780f5
Id:2,CompanyName:Planes R Us,ShipperType:Planes,DateCreated:2010-01-31T11:53:37.799937Z,UniqueRef:e02a73191f4b4e7a9c44eef5b5965d06

ADDED A PROSPECTIVE SHIPPER:
Id:4,CompanyName:Trucks R Us,ShipperType:Automobiles,DateCreated:2010-01-31T11:53:37.8539401Z,UniqueRef:67d7d4947ebc4b0ba5c4d42f5d903bec

CURRENT SHIPPERS AFTER POP n' PUSH:
Id:4,CompanyName:Trucks R Us,ShipperType:Automobiles,DateCreated:2010-01-31T11:53:37.8539401Z,UniqueRef:67d7d4947ebc4b0ba5c4d42f5d903bec
Id:1,CompanyName:Trains R Us,ShipperType:Trains,DateCreated:2010-01-31T11:53:37.7169323Z,UniqueRef:d17c5db0415b44b2ac5da7b6ebd780f5
Id:2,CompanyName:Planes R Us,ShipperType:Planes,DateCreated:2010-01-31T11:53:37.799937Z,UniqueRef:e02a73191f4b4e7a9c44eef5b5965d06

PROSPECTIVE SHIPPERS AFTER POP n' PUSH:

POPPED a SHIPPER:
Id:2,CompanyName:Planes R Us,ShipperType:Planes,DateCreated:2010-01-31T11:53:37.799937Z,UniqueRef:e02a73191f4b4e7a9c44eef5b5965d06

CURRENT SHIPPERS AFTER POP:
Id:4,CompanyName:Trucks R Us,ShipperType:Automobiles,DateCreated:2010-01-31T11:53:37.8539401Z,UniqueRef:67d7d4947ebc4b0ba5c4d42f5d903bec
Id:1,CompanyName:Trains R Us,ShipperType:Trains,DateCreated:2010-01-31T11:53:37.7169323Z,UniqueRef:d17c5db0415b44b2ac5da7b6ebd780f5

DELETING CURRENT AND PROSPECTIVE SHIPPERS:

D'autres exemples sont disponibles dans la [page d'exemples RedisExamples Redis] et dans la suite de tests complète

Numéro de vitesse

L'une des meilleures choses à propos de Redis est la vitesse - c'est rapide.

Cet exemple ci-dessous stocke et récupère l'intégralité de la base de données Northwind (3 202 enregistrements) en moins de 1,2 seconde - nous n'avons jamais été aussi rapides !

(Exécution dans un test unitaire VS.NET/R# sur un iMac de 3 ans)

using var client = new RedisClient();

var before = DateTime.Now;
client.StoreAll(NorthwindData.Categories);
client.StoreAll(NorthwindData.Customers);
client.StoreAll(NorthwindData.Employees);
client.StoreAll(NorthwindData.Shippers);
client.StoreAll(NorthwindData.Orders);
client.StoreAll(NorthwindData.Products);
client.StoreAll(NorthwindData.OrderDetails);
client.StoreAll(NorthwindData.CustomerCustomerDemos);
client.StoreAll(NorthwindData.Regions);
client.StoreAll(NorthwindData.Territories);
client.StoreAll(NorthwindData.EmployeeTerritories);

Console.WriteLine("Took {0}ms to store the entire Northwind database ({1} records)",
    (DateTime.Now - before).TotalMilliseconds, totalRecords);

before = DateTime.Now;
var categories = client.GetAll<Category>();
var customers = client.GetAll<Customer>();
var employees = client.GetAll<Employee>();
var shippers = client.GetAll<Shipper>();
var orders = client.GetAll<Order>();
var products = client.GetAll<Product>();
var orderDetails = client.GetAll<OrderDetail>();
var customerCustomerDemos = client.GetAll<CustomerCustomerDemo>();
var regions = client.GetAll<Region>();
var territories = client.GetAll<Territory>();
var employeeTerritories = client.GetAll<EmployeeTerritory>();

Console.WriteLine("Took {0}ms to get the entire Northwind database ({1} records)",
    (DateTime.Now - before).TotalMilliseconds, totalRecords);
/*
== EXAMPLE OUTPUT ==

Took 1020.0583ms to store the entire Northwind database (3202 records)
Took 132.0076ms to get the entire Northwind database (3202 records)
*/

Remarque :Le temps total nécessaire inclut une opération Redis supplémentaire pour chaque enregistrement afin de stocker l'identifiant dans un ensemble Redis pour chaque type, ainsi que la sérialisation et la désérialisation de chaque enregistrement à l'aide de TypeSerializer de Service Stack.

Numéro d'opérations Lex

Les nouvelles opérations d'ensembles triés ZRANGEBYLEX vous permettant d'interroger un ensemble trié de manière lexicale ont été ajoutées. Une bonne vitrine pour cela est disponible sur autocomplete.redis.io.

Ces nouvelles opérations sont disponibles sous forme de mappage 1:1 avec redis-server sur IRedisNativeClient :

public interface IRedisNativeClient
{
    ...
    byte[][] ZRangeByLex(string setId, string min, string max, int? skip, int? take);
    long ZLexCount(string setId, string min, string max);
    long ZRemRangeByLex(string setId, string min, string max);
}

Et les API plus conviviales sous IRedisClient :

public interface IRedisClient
{
    ...
    List<string> SearchSortedSet(string setId, string start=null, string end=null);
    long SearchSortedSetCount(string setId, string start=null, string end=null);
    long RemoveRangeFromSortedSetBySearch(string setId, string start=null, string end=null);
}

Tout comme les matchers de version NuGet, Redis utilise [ char pour exprimer l'inclusivité et ( char pour l'exclusivité. Depuis le IRedisClient Les API utilisent par défaut des recherches inclusives, ces deux API sont identiques :

Redis.SearchSortedSetCount("zset", "a", "c")
Redis.SearchSortedSetCount("zset", "[a", "[c")

Alternativement, vous pouvez spécifier une ou les deux limites comme étant exclusives en utilisant le ( préfixe, par exemple :

Redis.SearchSortedSetCount("zset", "a", "(c")
Redis.SearchSortedSetCount("zset", "(a", "(c")

D'autres exemples d'API sont disponibles dans LexTests.cs.

API HyperLog #

La branche de développement du serveur Redis (disponible lors de la sortie de la v3.0) comprend un algorithme ingénieux pour approximer les éléments uniques d'un ensemble avec une efficacité spatiale et temporelle maximale. Pour plus de détails sur son fonctionnement, consultez le blog du créateur de Redis, Salvatore, qui l'explique en détail. Essentiellement, cela vous permet de conserver un moyen efficace de compter et de fusionner des éléments uniques dans un ensemble sans avoir à stocker ses éléments. Un exemple simple en action :

redis.AddToHyperLog("set1", "a", "b", "c");
redis.AddToHyperLog("set1", "c", "d");
var count = redis.CountHyperLog("set1"); //4

redis.AddToHyperLog("set2", "c", "d", "e", "f");

redis.MergeHyperLogs("mergedset", "set1", "set2");

var mergeCount = redis.CountHyperLog("mergedset"); //6

Analyse des API #

Redis v2.8 a introduit une belle nouvelle opération SCAN qui fournit une stratégie optimale pour parcourir un jeu de clés entier d'instance redis en morceaux de taille gérable en utilisant uniquement un curseur côté client et sans introduire d'état de serveur. C'est une alternative plus performante et doit être utilisée à la place de KEYS dans le code d'application. SCAN et ses opérations associées pour traverser les membres des ensembles, des ensembles triés et des hachages sont désormais disponibles dans le client Redis dans les API suivantes :

public interface IRedisClient
{
    ...
    IEnumerable<string> ScanAllKeys(string pattern = null, int pageSize = 1000);
    IEnumerable<string> ScanAllSetItems(string setId, string pattern = null, int pageSize = 1000);
    IEnumerable<KeyValuePair<string, double>> ScanAllSortedSetItems(string setId, string pattern = null, int pageSize = 1000);
    IEnumerable<KeyValuePair<string, string>> ScanAllHashEntries(string hashId, string pattern = null, int pageSize = 1000);    
}

public interface IRedisClientAsync
{
    IAsyncEnumerable<string> ScanAllKeysAsync(string pattern = null, int pageSize, CancellationToken ct);
    IAsyncEnumerable<string> ScanAllSetItemsAsync(string setId, string pattern = null, int pageSize, CancellationToken ct);
    IAsyncEnumerable<KeyValuePair<string, double>> ScanAllSortedSetItemsAsync(string setId, string pattern = null, int pageSize, ct);
    IAsyncEnumerable<KeyValuePair<string, string>> ScanAllHashEntriesAsync(string hashId, string pattern = null, int pageSize, ct);
}

//Low-level API
public interface IRedisNativeClient
{
    ...
    ScanResult Scan(ulong cursor, int count = 10, string match = null);
    ScanResult SScan(string setId, ulong cursor, int count = 10, string match = null);
    ScanResult ZScan(string setId, ulong cursor, int count = 10, string match = null);
    ScanResult HScan(string hashId, ulong cursor, int count = 10, string match = null);
}

public interface IRedisNativeClientAsync 
{
    ValueTask<ScanResult> ScanAsync(ulong cursor, int count = 10, string match = null, CancellationToken ct);
    ValueTask<ScanResult> SScanAsync(string setId, ulong cursor, int count = 10, string match = null, CancellationToken ct);
    ValueTask<ScanResult> ZScanAsync(string setId, ulong cursor, int count = 10, string match = null, CancellationToken ct);
    ValueTask<ScanResult> HScanAsync(string hashId, ulong cursor, int count = 10, string match = null, CancellationToken ct);
}

Le IRedisClient fournit une API de niveau supérieur qui fait abstraction du curseur client pour exposer une séquence Enumerable paresseuse afin de fournir un moyen optimal de diffuser les résultats analysés qui s'intègre parfaitement à LINQ, par exemple :

var scanUsers = Redis.ScanAllKeys("urn:User:*");
var sampleUsers = scanUsers.Take(10000).ToList(); //Stop after retrieving 10000 user keys