skip to Main Content

I have a list of keys that I want to get from Redis. I wrote a function like this but it returns everything:

    public IOrderedEnumerable<Fields> GetValues(List<string> symbols)
    {
        var retVal = new List<Fields>();

        var patternStr = "[";

        int count = 0;
        foreach (var symbol in symbols)
        {
            patternStr += (symbol);

            if (++count != symbols.Count)
            {
                patternStr += ", ";
            }
        }

        patternStr += "]*";

        foreach (var ep in redis.GetEndPoints())
        {
            var server = redis.GetServer(ep);
            var keysList = server.Keys(database: 0, pattern: patternStr).ToList();

            var keys = keysList.ToArray();

            Console.WriteLine("Number of Symbols in this range{0} ", keys.Length);

            foreach (var rk in keys)
            {
                var myValTask = db.StringGetAsync(rk.ToString());
                var myVal = myValTask.Result;
                var jsonStr = myVal.ToString();
                ...

            }
            ...
         }

         ...

The section of code I believe is the problem. I just want Redis to return the subset of keys, and I am building a pattern by seperating them by "," :

    var patternStr = "[";

    int count = 0;
    foreach (var symbol in symbols)
    {
        patternStr += (symbol);

        if (++count != symbols.Count)
        {
            patternStr += ", ";
        }
    }

    patternStr += "]*";

I know I can get all the keys, then filter them once I get them, but I want to avoid the network thrashing…

Edit 1

BTW, the keys look like this:

127.0.0.1:6379> keys *
  1) "BBWI_2022-08-19"
  2) "ABBV_2023-01-20"
  3) "ZTS_2022-10-21"

2

Answers


  1. If I understand correctly, you have a set of discrete keys that you want to fetch in a single batch. If so, you can fetch all items (within reason, say < 1000 at a time) by passing a RedisKey[] array to StringGetAsync:

    var keys = symbols.Select(symbol => (RedisKey)symbol).ToArray();
    var values = await db.StringGetAsync(keys);
    // .. use values
    
    Login or Signup to reply.
  2. You can use Scan command on redis server like this:

     public async Task<List<string>> ScanKeysAsync(string match, string count)
            {
                var schemas=new List<string>();
                int nextCursor = 0;
                do
                {
                    RedisResult redisResult =await _redisServer.ExecuteAsync("SCAN", nextCursor.ToString(), "MATCH", match, "COUNT", count);
                    var innerResult = (RedisResult[])redisResult;
    
                    nextCursor = int.Parse((string)innerResult[0]);
    
                    List<string> resultLines = ((string[])innerResult[1]).ToList();
                    schemas.AddRange(resultLines);
                }
                while (nextCursor != 0);
    
                return schemas;
            }
    

    and in your case would be something like this:

    var keys=await ScanKeysAsync("BBWI*",10);//return max 10 occurance of pattern
    

    But I recommend to use Scan in very special scenarios because it acts as a cursor and will iterate between all keys in redis to find match and also please read this https://redis.io/commands/scan

    Test

     var redis = scope.ServiceProvider.GetRequiredService<IDatabase>();
    
    await redis.StringSetAsync("BBWI_2022-08-19", "test1",TimeSpan.FromMinutes(5));
    await redis.StringSetAsync("BBWI_20fd22-08-19", "test2", TimeSpan.FromMinutes(5));
    await redis.StringSetAsync("ABBV_2023-08-19", "test3", TimeSpan.FromMinutes(5));
    
    var foundKeys = await ScanKeysAsync("BBW*", "10");
    //BBWI_2022-08-19
    //BBWI_20fd22-08-19
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search