Tom Gullen
Tom Gullen

Reputation: 61737

StackExchange Redis delete all keys that start with

I have a key in the format:

Error.1
Error.24
Error.32

Using StackExchange.Redis, how would I go about KeyDelete on all keys that match the format Error.?

On another answer I've seen the LUA script:

EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 Error.*

But I'm unsure how to call this using Database.ScriptEvaluate()

Upvotes: 7

Views: 22725

Answers (3)

Dave Black
Dave Black

Reputation: 8019

And the new version with C# Asynchronous Streaming via IAsyncEnumerable available in Redis.StackExchange v2.1.0-preview.23 and above.

NOTE: this version uses SCAN instead of KEYS if your Redis Instance supports that feature. This is a huge performance boost. You should also make sure your instance of ConnectionMultiplexer is a singleton - i.e. same instance used for the lifetime of the app.

I should also callout that Redis wildcard support allows for pretty flexible patterns. In my implementation (below), I only had a need to have a '*' at the end of the key, so that is all it is coded for. If you need additional wildcard support, you can implement the Redis wildcard supported glob-style patterns here:

  • h?llo matches hello, hallo and hxllo
  • h*llo matches hllo and heeeello
  • h[ae]llo matches hello and hallo, but not hillo
  • h[^e]llo matches hallo, hbllo, ... but not hello
  • h[a-b]llo matches hallo and hbllo

Use \ to escape special characters if you want to match them verbatim.

using Microsoft.Extensions.Caching.Distributed;
using StackExchange.Redis;

private readonly IDistributedCache _cache;
private readonly IConnectionMultiplexer _connectionMultiplexer;

public CacheRepository(IDistributedCache cache, IConnectionMultiplexer connectionMultiplexer)
{
    _cache = cache;
    _connectionMultiplexer = connectionMultiplexer;
}

public async Task RemoveWithWildCardAsync(string keyRoot)
{
    if (string.IsNullOrWhiteSpace(keyRoot))
        throw new ArgumentException("Value cannot be null or whitespace.", nameof(keyRoot));

    // get all the keys* and remove each one
    await foreach (var key in GetKeysAsync(keyRoot + "*"))
    {
        await _cache.RemoveAsync(key);
    }
}

public async IAsyncEnumerable<string> GetKeysAsync(string pattern)
{
    if (string.IsNullOrWhiteSpace(pattern))
        throw new ArgumentException("Value cannot be null or whitespace.", nameof(pattern));

    foreach (var endpoint in _connectionMultiplexer.GetEndPoints())
    {
        var server = _connectionMultiplexer.GetServer(endpoint);
        await foreach (var key in server.KeysAsync(pattern: pattern))
        {
            yield return key.ToString();
        }
    }
}

public IEnumerable<RedisFeatures> GetRedisFeatures()
{
    foreach (var endpoint in _connectionMultiplexer.GetEndPoints())
    {
        var server = _connectionMultiplexer.GetServer(endpoint);
        yield return server.Features;
    }
}

Upvotes: 9

Sajad Jalilian
Sajad Jalilian

Reputation: 176

I spend some time not getting any key using accepted answer

For pattern, use something like this.

server.Keys(pattern: "*Error.*")

You should add stars before and after your pattern.

Upvotes: 1

Cristi Pufu
Cristi Pufu

Reputation: 9095

Just get all keys matching the pattern, iterate and delete, something like this:

using (var redisConnection = ConnectionMultiplexer.Connect(...))
{
    var server = redisConnection.GetServer(endpoint:...);

    if (server != null)
    {
         foreach (var key in server.Keys(pattern: "Error.*"))
         {
               redisConnection.Database.KeyDelete(key);
         }
    }
}

Later edit:

Example of setting up a Redis Connection: https://gist.github.com/cristipufu/9ad47caf3dba60d712484d0c880597b9

The multiplexer should be stored and reused, not disposed and recreated each time. https://stackexchange.github.io/StackExchange.Redis/Basics

Performance can be significantly increased by adjusting / specifying the pageSize parameter of the Keys call. Its default value is 10. Try 1,000.

StackExchange.Redis server.Keys(pattern:"IsVerySlow*")

Upvotes: 10

Related Questions