Redis Python - 如何根据特定模式删除所有键在python中,无需python迭代
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21975228/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Redis Python - how to delete all keys according to a specific pattern In python, without python iterating
提问by alonisser
I'm writing a django management command to handle some of our redis caching. Basically, I need to choose all keys, that confirm to a certain pattern (for example: "prefix:*") and delete them.
我正在编写一个 django 管理命令来处理我们的一些 redis 缓存。基本上,我需要选择所有键,确认某个模式(例如:“前缀:*”)并删除它们。
I know I can use the cli to do that:
我知道我可以使用 cli 来做到这一点:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
But I need to do this from within the app. So I need to use the python binding (I'm using py-redis). I have tried feeding a list into delete, but it fails:
但我需要在应用程序中执行此操作。所以我需要使用 python 绑定(我使用的是 py-redis)。我曾尝试将列表输入删除,但失败了:
from common.redis_client import get_redis_client
cache = get_redis_client()
x = cache.keys('prefix:*')
x == ['prefix:key1','prefix:key2'] # True
# And now
# 现在
cache.delete(x)
# returns 0 . nothing is deleted
# 返回 0 。什么都没有删除
I know I can iterate over x:
我知道我可以遍历 x:
for key in x:
cache.delete(key)
But that would be losing redis awesome speed and misusing its capabilities. Is there a pythonic solution with py-redis, without iteration and/or the cli?
但这将失去 redis 惊人的速度并滥用其功能。是否有带有 py-redis 的 pythonic 解决方案,无需迭代和/或 cli?
Thanks!
谢谢!
采纳答案by Dirk Eddelbuettel
I think the
我觉得
for key in x: cache.delete(key)
is pretty good and concise. deletereally wants one key at a time, so you have to loop.
非常好,简洁。 delete一次真的想要一个键,所以你必须循环。
Otherwise, this previous question and answerpoints you to a lua-based solution.
否则,前面的问题和答案将指向基于 lua 的解决方案。
回答by Blackeagle52
cache.delete(*keys)solution of Dirk works fine, but make sure keys isn't empty to avoid a redis.exceptions.ResponseError: wrong number of arguments for 'del' command.
cache.delete(*keys)Dirk 的解决方案工作正常,但请确保键不为空以避免redis.exceptions.ResponseError: wrong number of arguments for 'del' command.
If you are sure that you will always get a result: cache.delete(*cache.keys('prefix:*') )
如果你确定你总会得到一个结果: cache.delete(*cache.keys('prefix:*') )
回答by Gleb
Btw, for the django-redis you can use the following (from https://niwinz.github.io/django-redis/latest/):
顺便说一句,对于 django-redis,您可以使用以下内容(来自https://niwinz.github.io/django-redis/latest/):
from django.core.cache import cache
cache.delete_pattern("foo_*")
回答by Alex Toderita
Use SCAN iterators: https://pypi.python.org/pypi/redis
使用 SCAN 迭代器:https: //pypi.python.org/pypi/redis
for key in r.scan_iter("prefix:*"):
r.delete(key)
回答by James
From the Documentation
从文档
delete(*names) Delete one or more keys specified by names
delete(*names) Delete one or more keys specified by names
This just wants an argument per key to delete and then it will tell you how many of them were found and deleted.
这只是想要删除每个键的参数,然后它会告诉您找到并删除了多少个。
In the case of your code above I believe you can just do:
对于上面的代码,我相信您可以这样做:
redis.delete(*x)
But I will admit I am new to python and I just do:
但我承认我是 python 的新手,我只是这样做:
deleted_count = redis.delete('key1', 'key2')
回答by radtek
Here is a full working example using py-redis:
这是一个使用py-redis的完整工作示例:
from redis import StrictRedis
cache = StrictRedis()
def clear_ns(ns):
"""
Clears a namespace
:param ns: str, namespace i.e your:prefix
:return: int, cleared keys
"""
count = 0
ns_keys = ns + '*'
for key in cache.scan_iter(ns_keys):
cache.delete(key)
count += 1
return count
You can also do scan_iterto get all the keys into memory, and then pass all the keys to deletefor a bulk delete but may take a good chunk of memory for larger namespaces. So probably best to run a deletefor each key.
您还可以scan_iter将所有键放入内存,然后将所有键传递给delete以进行批量删除,但对于较大的命名空间可能会占用大量内存。所以可能最好delete为每个键运行一个。
Cheers!
干杯!
UPDATE:
更新:
Since writing the answer, I started using pipelining feature of redis to send all commands in one request and avoid network latency:
自从写了答案,我开始使用 redis 的流水线功能在一个请求中发送所有命令并避免网络延迟:
from redis import StrictRedis
cache = StrictRedis()
def clear_cache_ns(ns):
"""
Clears a namespace in redis cache.
This may be very time consuming.
:param ns: str, namespace i.e your:prefix*
:return: int, num cleared keys
"""
count = 0
pipe = cache.pipeline()
for key in cache.scan_iter(ns):
pipe.delete(key)
count += 1
pipe.execute()
return count
UPDATE2 (Best Performing):
UPDATE2(最佳表现):
If you use scaninstead of scan_iter, you can control the chunk size and iterate through the cursor using your own logic. This also seems to be a lot faster, especially when dealing with many keys. If you add pipelining to this you will get a bit of a performance boost, 10-25% depending on chunk size, at the cost of memory usage since you will not send the execute command to Redis until everything is generated. So I stuck with scan:
如果使用scan代替scan_iter,则可以控制块大小并使用自己的逻辑遍历游标。这似乎也快了很多,尤其是在处理许多键时。如果您为此添加流水线,您将获得一些性能提升,10-25% 取决于块大小,以内存使用为代价,因为在生成所有内容之前您不会将执行命令发送到 Redis。所以我坚持扫描:
from redis import StrictRedis
cache = StrictRedis()
CHUNK_SIZE = 5000
def clear_ns(ns):
"""
Clears a namespace
:param ns: str, namespace i.e your:prefix
:return: int, cleared keys
"""
cursor = '0'
ns_keys = ns + '*'
while cursor != 0:
cursor, keys = cache.scan(cursor=cursor, match=ns_keys, count=CHUNK_SIZE)
if keys:
cache.delete(*keys)
return True
Here are some benchmarks:
以下是一些基准:
5k chunks using a busy Redis cluster:
使用繁忙的 Redis 集群的 5k 块:
Done removing using scan in 4.49929285049
Done removing using scan_iter in 98.4856731892
Done removing using scan_iter & pipe in 66.8833789825
Done removing using scan & pipe in 3.20298910141
5k chunks and a small idle dev redis (localhost):
5k 块和一个小的空闲 dev redis(本地主机):
Done removing using scan in 1.26654982567
Done removing using scan_iter in 13.5976779461
Done removing using scan_iter & pipe in 4.66061878204
Done removing using scan & pipe in 1.13942599297
回答by carton.swing
According to my test, it will costs too much time if I use scan_itersolution (as Alex Toderita wrote).
根据我的测试,如果我使用scan_iter解决方案会花费太多时间(正如Alex Toderita 所写)。
Therefore, I prefer to use:
因此,我更喜欢使用:
from redis.connection import ResponseError
try:
redis_obj.eval('''return redis.call('del', unpack(redis.call('keys', ARGV[1])))''', 0, 'prefix:*')
except ResponseError:
pass
The prefix:*is the pattern.
这prefix:*就是模式。
refers to: https://stackoverflow.com/a/16974060
回答by Jijo
Use delete_pattern: https://niwinz.github.io/django-redis/latest/
使用delete_pattern:https://niwinz.github.io/django-redis/latest/
from django.core.cache import cache
cache.delete_pattern("prefix:*")
回答by Lynn Han
You can use a specific pattern to match all keys and delete them:
您可以使用特定模式来匹配所有键并删除它们:
import redis
client = redis.Redis(host='192.168.1.106', port=6379,
password='pass', decode_responses=True)
for key in client.keys('prefix:*'):
client.delete(key)

