Redis/Jedis - Delete by pattern?
Solution 1
It seems, for Jedis, to "delete by pattern" is basically getting all the keys of a specific pattern then loop through it.
ie
Set<String> keys = jedis.keys(pattern);
for (String key : keys) {
jedis.del(key);
}
Solution 2
KEYS is not recommended to use due to its inefficiencies when used in production. Please see https://redis.io/commands/keys. Instead, it is better to use SCAN. Additionally, a more efficient call than repeated calls to jedis.del() is to make one single call to jedis to remove the matching keys, passing in an array of keys to delete. A more efficient solution is presented below:
Set<String> matchingKeys = new HashSet<>();
ScanParams params = new ScanParams();
params.match("sample_pattern:*");
try(Jedis jedis = jedisPoolFactory.getPool().getResource()) {
String nextCursor = "0";
do {
ScanResult<String> scanResult = jedis.scan(nextCursor, params);
List<String> keys = scanResult.getResult();
nextCursor = scanResult.getStringCursor();
matchingKeys.addAll(keys);
} while(!nextCursor.equals("0"));
if (matchingKeys.size() == 0) {
return;
}
jedis.del(matchingKeys.toArray(new String[matchingKeys.size()]));
}
Solution 3
You should try using eval. I'm no Lua expert, but this code works.
private static final String DELETE_SCRIPT_IN_LUA =
"local keys = redis.call('keys', '%s')" +
" for i,k in ipairs(keys) do" +
" local res = redis.call('del', k)" +
" end";
public void deleteKeys(String pattern) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
if (jedis == null) {
throw new Exception("Unable to get jedis resource!");
}
jedis.eval(String.format(DELETE_SCRIPT_IN_LUA, pattern));
} catch (Exception exc) {
if (exc instance of JedisConnectionException && jedis != null) {
jedisPool.returnBrokenResource(jedis);
jedis = null;
}
throw new RuntimeException("Unable to delete that pattern!");
} finally {
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
}
And then call:
deleteKeys("temp:keys:*");
This guarantees a one server-side call, multiple delete operation.
Solution 4
You can do it with the Redisson in one line:
redisson.getKeys().deleteByPattern(pattern)
Solution 5
You can do it with bash:
$ redis-cli KEYS "sample_pattern:*" | xargs redis-cli DEL
iCodeLikeImDrunk
Updated on October 16, 2020Comments
-
iCodeLikeImDrunk over 3 years
Normally, I get the key set then use a look to delete each key/value pair.
Is it possible to just delete all keys via pattern?
ie:
Del sample_pattern:*
-
iCodeLikeImDrunk over 10 yearssorry, forgot to mention that i want to do this in java code. but this is useful.
-
Agis over 10 years@yaojiang I never wrote a line of Java but here's my take, see the updated answer.
-
iCodeLikeImDrunk over 10 yearsno dice. it looks like the jedis implementation only allows me to do something like jedis.del(key1, key2, key3,...);
-
Agis over 10 years@yaojiang Oh, I thought
jedis.keys()
would return a collection of keys. What does it return btw? -
iCodeLikeImDrunk over 10 yearsone or more string args, or byte[].
-
dbaq about 7 yearsScan is better. But you can reduce the number of call to jedis by doing
Set<String> keys = jedis.keys(pattern); jedis.del(keys.toArray(new String[keys.size()]));
-
febot over 6 yearsI wonder twho things - why KEYS is so ineffective, and whether SCANning of non-trivial entries (say, 10kb JSONs) is really more effective than using KEYS. I mean - keys is basically like SCAN, only dropping the content and returning in one bulk. Which wou need to do here anyway.
-
Kirk Backus about 6 yearsSince Redis is generally considered to be single-threaded, the KEYS command could block for seconds if the set is sufficiently large. In many production environments, waiting for even a couple milliseconds could cause major performance problems since Redis is assumed to be fast.
-
OrangeBumblebee over 2 yearsMuch more efficient than the answer marked as correct. Thank you. However, you must instantiate jedisPool before using it in the try block: JedisPool jedisPool = new JedisPool(); Further, all that needs to be called is jedisPool.getResource(). The factory part is no longer necessary, nor is the .getPool() method called on it.
-
OrangeBumblebee over 2 yearsA more efficient way to do it without using KEYS can be found below: stackoverflow.com/a/42702672/11150418
-
NanoNova about 2 yearsI think
scanResult.getStringCursor()
is deprecated. Replaced withscanResult.getCursor()
.