Існує публікація про команду Redis, щоб отримати всі доступні ключі, але я хотів би зробити це за допомогою Python.
Будь-який спосіб зробити це?
Відповіді:
Використовуйте scan_iter()
scan_iter()
перевершує keys()
для великої кількості клавіш, оскільки дає вам ітератор, яким ви можете скористатися, а не намагатися завантажити всі ключі в пам’ять.
У мене в реді було 1B записів, і я ніколи не міг отримати достатньо пам’яті, щоб повернути всі клавіші одночасно.
КЛЮЧІ СКАНУВАННЯ ОДИН ЗА ОДИН
Ось фрагмент python, за допомогою якого scan_iter()
можна отримати всі ключі з магазину, що відповідають шаблону, і видалити їх по одному:
import redis
r = redis.StrictRedis(host='localhost', port=6379, db=0)
for key in r.scan_iter("user:*"):
# delete the key
r.delete(key)
СКАНУВАННЯ ПАРТІЯМИ
Якщо у вас є дуже великий список ключів для сканування - наприклад, більше> 100 тис. Ключів, буде ефективніше сканувати їх групами, наприклад:
import redis
from itertools import izip_longest
r = redis.StrictRedis(host='localhost', port=6379, db=0)
# iterate a list in batches of size n
def batcher(iterable, n):
args = [iter(iterable)] * n
return izip_longest(*args)
# in batches of 500 delete keys matching user:*
for keybatch in batcher(r.scan_iter('user:*'),500):
r.delete(*keybatch)
Я порівняв цей скрипт і виявив, що використання пакета розміром 500 було в 5 разів швидше, ніж сканування ключів по одному. Я протестував різні розміри партії (3 500 500 000 5000) і виявив, що розмір партії 500 видається оптимальним.
Зауважте, що незалежно від того, чи використовуєте ви метод scan_iter()
або keys()
, операція не є атомною і може провалитися частково.
ЦІЛЬКИ УНИКНІТЬ ВИКОРИСТАННЯ ЯРГАРІВ НА КОМАНДОВІЙ ЛІНІЇ
Я не рекомендую цей приклад, який я знайшов повтореним в іншому місці. Це не вдасться для клавіш Unicode і неймовірно повільне для навіть помірної кількості клавіш:
redis-cli --raw keys "user:*"| xargs redis-cli del
У цьому прикладі xargs створює новий процес redis-cli для кожного ключа! це погано.
Я оцінив цей підхід у 4 рази повільніше, ніж перший приклад python, коли він видаляв кожен ключ по одному і в 20 разів повільніше, ніж видалення партіями по 500.
Так, використовуйте keys()
з модуля StrictRedis:
>>> import redis
>>> r = redis.StrictRedis(host=YOUR_HOST, port=YOUR_PORT, db=YOUR_DB)
>>> r.keys()
Якщо вказати нульовий шаблон, ви отримаєте їх усі. За посиланням на сторінку:
клавіші (шаблон = '*')
Повертає список ключів, що відповідають шаблону
SCAN
команду, оскільки це зараз кращий спосіб отримати всі ключі з O (1) часовою складністю кожного запиту. (та O (N) для всіх запитів)
r.keys()
є досить повільним, коли ви намагаєтеся зіставити шаблон, а не просто повертаєте всі ключі. Подумайте про використання, scan
як пропонується у відповіді нижче
import redis
r = redis.Redis("localhost", 6379)
for key in r.scan_iter():
print key
за допомогою бібліотеки Pyredis
Доступно з 2.8.0.
Складність часу: O (1) для кожного дзвінка. O (N) для повної ітерації, включаючи достатню кількість викликів команд, щоб курсор повернувся до 0. N - кількість елементів всередині колекції.
Я хотів би додати приклад коду для відповіді Патріка та інші.
Це показує результати як за допомогою клавіш, так і методу scan_iter. І зверніть увагу, що Python3 використовує zip_longest замість izip_longest. Наведений нижче код переглядає всі клавіші та відображає їх. Я встановив розмір пакета як змінну 12, щоб зменшити результат.
Я написав це, щоб краще зрозуміти, як працювало групування ключів.
import redis
from itertools import zip_longest
\# connection/building of my redisObj omitted here
\# iterate a list in batches of size n
def batcher(iterable, n):
args = [iter(iterable)] * n
return zip_longest(*args)
result1 = redisObj.get("TestEN")
print(result1)
result2 = redisObj.get("TestES")
print(result2)
print("\n\nLoop through all keys:")
keys = redisObj.keys('*')
counter = 0
print("len(keys)=", len(keys))
for key in keys:
counter +=1
print (counter, "key=" +key, " value=" + redisObj.get(key))
print("\n\nLoop through all keys in batches (using itertools)")
\# in batches of 500 delete keys matching user:*
counter = 0
batch_counter = 0
print("Try scan_iter:")
for keybatch in batcher(redisObj.scan_iter('*'), 12):
batch_counter +=1
print(batch_counter, "keybatch=", keybatch)
for key in keybatch:
if key != None:
counter += 1
print(" ", counter, "key=" + key, " value=" + redisObj.get(key))
Приклад виводу:
Loop through all keys:
len(keys)= 2
1 key=TestES value=Ola Mundo
2 key=TestEN value=Hello World
Loop through all keys in batches (using itertools)
Try scan_iter:
1 keybatch= ('TestES', 'TestEN', None, None, None, None, None, None, None, None, None, None)
1 key=TestES value=Ola Mundo
2 key=TestEN value=Hello World
Зверніть увагу, що команди redis є однопотоковими, тому виконання клавіш () може заблокувати інші дії redis. Дивіться чудовий пост тут, який пояснює це більш докладно: SCAN проти KEYS продуктивності в Redis
Додаток до прийнятої відповіді вище.
scan_iter
можна використовувати з count
параметром для того, щоб сказати redis здійснювати пошук за кількістю ключів під час однієї ітерації. Це може значно пришвидшити отримання ключів, особливо при використанні з відповідним шаблоном та на великих клавішних просторах.
Будьте обережні, жорсткі, використовуючи дуже високі значення для підрахунку, оскільки це може зіпсувати продуктивність для інших паралельних запитів.
https://docs.keydb.dev/blog/2020/08/10/blog-post/ Ось стаття з додатковою інформацією та деякими орієнтирами.