web-dev-qa-db-ja.com

Redis Python-特定のパターンに従ってすべてのキーを削除する方法pythonで、python繰り返し

Django redisキャッシュの一部を処理する管理コマンドを書いています。基本的に、特定のパターンを確認するすべてのキーを選択する必要があります(例: "prefix:*")それらを削除します。

私はそれを行うためにCLIを使用できることを知っています:

redis-cli KEYS "prefix:*" | xargs redis-cli DEL

しかし、私はアプリ内からこれを行う必要があります。だから私は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

# そしていま

cache.delete(x) 

#は0を返します。何も削除されません

私はxを反復できることを知っています:

for key in x:
   cache.delete(key)

しかし、それはredisの驚くべき速度を失い、その機能を誤用します。反復および/またはCLIなしで、py-redisを使用したPythonソリューションがありますか?

ありがとう!

30
alonisser

私は思います

 for key in x: cache.delete(key)

かなり簡潔です。 deleteは実際には一度に1つのキーが必要なので、ループする必要があります。

それ以外の場合、この 前の質問と回答 はluaベースのソリューションを示します。

13

SCANイテレータを使用します: https://pypi.python.org/pypi/redis

for key in r.scan_iter("prefix:*"):
    r.delete(key)
25
Alex Toderita

ドキュメント から

delete(*names)
    Delete one or more keys specified by names

これは、キーごとに削除する引数を必要とするだけで、それらのどれだけが見つかって削除されたかを示します。

上記のコードの場合、私はあなたがちょうどできると信じています:

    redis.delete(*x)

しかし、私はpythonが初めてだということを認めます。

    deleted_count = redis.delete('key1', 'key2')
8
James

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

scan_iterを実行してすべてのキーをメモリに取得し、すべてのキーをdeleteに渡して一括削除することもできますが、より大きなネームスペースでは十分なメモリを使用できます。したがって、おそらく各キーに対してdeleteを実行するのが最善です。

乾杯!

更新:

答えを書いてから、私はredisのパイプライン機能を使用して、すべてのコマンドを1つのリクエストで送信し、ネットワーク遅延を回避し始めました。

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_keys):
        pipe.delete(key)
        count += 1
    pipe.execute()
    return count

更新2(最高のパフォーマンス):

scan_iterの代わりにscanを使用する場合、独自のロジックを使用してチャンクサイズを制御し、カーソルを反復処理できます。また、これは、特に多くのキーを処理する場合、はるかに高速であるようです。これにパイプラインを追加すると、すべてが生成されるまで実行コマンドをRedisに送信しないため、メモリ使用量を犠牲にして、チャンクサイズに応じて10〜25%のパフォーマンスが少し向上します。だから私はスキャンで立ち往生しました:

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

ベンチマークは次のとおりです。

忙しい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チャンクと小さなアイドルdev redis(localhost):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

8
radtek

cache.delete(*keys) Dirkのソリューションは正常に動作しますが、_redis.exceptions.ResponseError: wrong number of arguments for 'del' command_を避けるためにキーが空でないことを確認してください。

常に結果が得られることが確実な場合:cache.delete(*cache.keys('prefix:*') )

4
Blackeagle52

私のテストによると、scan_iterソリューションを使用すると時間がかかりすぎます( Alex Toderitaが書いたように )。

したがって、私は使用することを好む:

from redis.connection import ResponseError

try:
    redis_obj.eval('''return redis.call('del', unpack(redis.call('keys', ARGV[1])))''', 0, 'prefix:*')
except ResponseError:
    pass

prefix:*はパターンです。


参照: https://stackoverflow.com/a/1697406

3
carton.swing

ところで、Django-redisの場合、次を使用できます( https://niwinz.github.io/Django-redis/latest/ から):

from Django.core.cache import cache
cache.delete_pattern("foo_*")
3
Gleb

Delete_patternを使用: https://niwinz.github.io/Django-redis/latest/

from Django.core.cache import cache
cache.delete_pattern("prefix:*")
1
Jijo

特定のパターンを使用してすべてのキーを照合し、それらを削除できます。

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)
1
Lynn Han