В этой главе мы расскажем, как работать с redis в Python. redis — это база данных «ключ — значение». Значение поддерживает string, list, set, zset (упорядоченное множество), hash (хеш-тип) и другие типы.
Для получения дополнительной информации о redis вы можете обратиться к нашемуучебнику по redis, обратите внимание, что перед началом изучения этой главы вам нужно убедиться, что ваш сервис redis установлен.
Интерфейс запуска redis выглядит следующим образом:
Запуск redis
75858:C 25 Окт 11:43:34.329 # Предупреждение: конфигурационный файл не указан, используется конфигурация по умолчанию. Чтобы указать конфигурационный файл, используйте ./redis-server /path/to/redis.conf
75858:M 25 Окт 11:43:34.331 * Увеличено максимальное количество открытых файлов до 10032 (изначально было установлено в 256).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.0.3 (255fcb1a/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Работает в автономном режиме
|`-._`-...-` __...-.``-._|'` _.-'| Порт: 6379
| `-._ `._ / _.-' | PID: 75858
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
75858:M 25 Окт 11:43:34.337 # Сервер запущен, версия Redis 3.0.3
75858:M 25 Окт 11:43:34.339 * БД загружена с диска: 0.002 секунд
75858:M 25 Окт 11:43:34.339 * Сервер теперь готов принимать соединения на порту 6379
Вы можете видеть, что номер порта по умолчанию равен6379。
Установите модуль redis
Чтобы использовать redis в Python, сначала нужно установить модуль redis:
sudo pip3 install redis или sudo easy_install redis или sudo python setup.py install
Адрес исходного кода:https://github.com/WoLpH/redis-py
Проверьте, успешна ли установка:
>>> import redis
>>> r = redis.StrictRedis(host='localhost', port=6379, db=0)
>>> r.set('foo', 'bar')
True
>>> r.get('foo')
'bar'
redis предоставляет два класса: Redis и StrictRedis. StrictRedis используется для реализации большинства официальных команд, а Redis является подклассом StrictRedis и используется для обратной совместимости со старыми версиями.
Результат, полученный из redis, по умолчанию представляет собой bytes; можно задатьdecode_responses=Trueчтобы преобразовать его в строку.
Пример
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
r.set('name', 'example') # Установить значение, соответствующее name
print(r['name'])
print(r.get('name')) # Получить значение, соответствующее ключу name
print(type(r.get('name'))) # Проверить тип
Результат вывода:
example example <class 'str'>
Пул соединений
redis-py использует пул соединений для управления всеми подключениями к серверу redis, избегая накладных расходов на установление и освобождение соединений каждый раз.
По умолчанию каждый экземпляр Redis поддерживает собственный пул соединений. Можно напрямую создать пул соединений, а затем передать его как параметр в Redis, чтобы несколько экземпляров Redis могли совместно использовать один пул соединений.
Пример
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
r.set('name', 'example') # Установить значение, соответствующее name
print(r.get('name')) # Получить значение, соответствующее ключу name
Основные команды redis String
set(name, value, ex=None, px=None, nx=False, xx=False)
Устанавливает значение в Redis. По умолчанию, если оно не существует, создаёт его; если существует, изменяет его.
Параметры:
- ex - время истечения (секунды)
- px - время истечения (миллисекунды)
- nx - Если установлено значение True, текущая операция set выполняется только если name не существует.
- xx - Если установлено значение True, текущая операция set выполняется только если name существует.
1. ex - время истечения (секунды). Здесь время истечения - 3 секунды. Через 3 секунды значение ключа food становится None.
Пример
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.set('food', 'mutton', ex=3) # Ключ - "food", значение - "mutton". Сохранить пару ключ-значение в кэш redis.
print(r.get('food')) # mutton. Получить значение, соответствующее ключу food.
2. px - время истечения (миллисекунды). Здесь время истечения - 3 миллисекунды. Через 3 миллисекунды значение ключа foo становится None.
Пример
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.set('food', 'beef', px=3)
print(r.get('food'))
3. nx - Если установлено True, текущая операция set выполняется только когда name не существует (создание).
Пример
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
print(r.set('fruit', 'watermelon', nx=True)) # True--не существует
# Если ключ fruit не существует, вывод — True; если ключ fruit уже существует, вывод — None.
4. xx - Если установлено True, текущая операция set выполняется только когда name существует (изменение).
Пример
# Если ключ fruit уже существует, вывод — True; если ключ fruit не существует, вывод — None.
5.setnx(name, value)
Установить значение; выполнять операцию set только когда name не существует (добавление).
print(r.setnx('fruit1', 'banana')) # fruit1不存在,输出为True
6.setex(name, time, value)
Установить значение
Параметры:
time — время истечения (числовое количество секунд или объект timedelta)
Пример
import time
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.setex("fruit2", 5, "orange")
time.sleep(5)
print(r.get('fruit2')) # Через 5 секунд значение меняется с orange на None.
7.psetex(name, time_ms, value)
Установить значение
Параметры:
time_ms — время истечения (числовое количество миллисекунд или объект timedelta)
Пример
time.sleep(5)
print(r.get('fruit3')) # Через 5000 миллисекунд значение меняется с apple на None.
8.mset(*args, **kwargs)
Пакетная установка значений
Например:
Пример
r.mset(k1="v1", k2="v2") # Здесь k1 и k2 нельзя брать в кавычки; установить несколько пар ключ-значение сразу.
print(r.mget("k1", "k2")) # Получить значения для нескольких ключей сразу.
print(r.mget("k1"))
9.mget(keys, *args)
Пакетное получение
Например:
Пример
print(r.mget(['k1', 'k2']))
print(r.mget("fruit", "fruit1", "fruit2", "k1", "k2")) # Пакетно извлечь значения, соответствующие ключам в текущем кэше redis.
10.getset(name, value)
Установить новое значение и получить исходное значение
print(r.getset("food", "barbecue")) # 设置的新值是barbecue 设置前的值是beef
11.getrange(key, start, end)
Получить подпоследовательность (по байтам, а не по символам)
Параметры:
- name - имя Redis
- start - начальная позиция (байт)
- end - конечная позиция (байт)
Например: "君惜大大", 0-3 означает "君"
Пример
print(r.getrange("cn_name", 0, 2)) # Получить байты с индекса 0-2, первые 3 байта, "君", операция среза (один китайский символ занимает 3 байта, одна буква занимает 1 байт, каждый байт — 8 бит)
print(r.getrange("cn_name", 0, -1)) # Получить все байты, "Junxi Dada", операция среза
r.set("en_name","junxi") # буквы
print(r.getrange("en_name", 0, 2)) # Получить байты с индекса 0-2, первые 3 байта, "jun", операция среза (один китайский символ занимает 3 байта, одна буква занимает 1 байт, каждый байт — 8 бит)
print(r.getrange("en_name", 0, -1)) # Получить все байты, "junxi", операция среза
12.setrange(name, offset, value)
Изменить содержимое строки, заменить, начиная с указанного индекса строки (если новое значение слишком длинное, добавить в конец).
Параметры:
- offset - индекс строки в байтах (один китайский символ — три байта)
- value — значение для установки
Пример
print(r.get("en_name")) # jccci: исходное значение — junxi, заменить начиная с индекса 1 на ccc, получается jccci
13.setbit(name, offset, value)
Работа с битами двоичного представления значения, соответствующего name
Параметры:
- name — имя в Redis
- offset — индекс бита (перед индексацией преобразуйте значение в двоичное представление)
- value — значение может быть только 1 или 0
Примечание: если в Redis есть соответствующая запись: n1 = "foo",
тогда двоичное представление строки foo: 01100110 01101111 01101111
Итак, если выполнить setbit('n1', 7, 1), то 7-й бит устанавливается в 1,
тогда итоговое двоичное представление становится 01100111 01101111 01101111, то есть: "goo"
Расширение, преобразовать в двоичное представление:
Пример
source = "foo"
for i in source:
num = ord(i)
print bin(num).replace('b','')
В частности, что, если source — это китайские иероглифы "Chen Siwei"?
Ответ: для utf-8 каждый китайский иероглиф занимает 3 байта, поэтому "Chen Siwei" содержит 9 байт. Для китайских иероглифов при использовании цикла for он будет перебирать по байтам. Во время итерации преобразуйте каждый байт в десятичное число, затем преобразуйте десятичное число в двоичное. 11100110 10101101 10100110 11100110 10110010 10011011 11101001 10111101 10010000
14.getbit(name, offset)
Получить значение определённого бита (0 или 1) в двоичном представлении значения, соответствующего name
print(r.getbit("foo1", 0)) # 0 foo1 对应的二进制 4个字节 32位 第0位是0还是1
15.bitcount(key, start=None, end=None)
Получить количество единиц в двоичном представлении значения, соответствующего name
Параметры:
- key — имя в Redis
- start — начальная позиция в байтах
- end — конечная позиция в байтах
Пример
print(r.bitcount("foo",0,1)) # 11 обозначает количество вхождений 1 в первых 2 байтах
16.bitop(operation, dest, *keys)
Получить несколько значений, выполнить побитовые операции над значениями и сохранить итоговый результат в значение, соответствующее новому имени
Параметры:
- operation — AND (and), OR (or), NOT (not), XOR (исключающее ИЛИ)
- dest — новое имя в Redis
- *keys — имена в Redis для поиска
e.g.:
bitop("AND", 'new_name', 'n1', 'n2', 'n3')
Получить значения, соответствующие n1, n2, n3 в Redis, затем выполнить побитовую операцию над всеми значениями (найти объединение), затем сохранить результат в значение, соответствующее new_name
Пример
r.set("foo1","2") # 0110010
print(r.mget("foo","foo1")) # ['goo1', 'baaanew']
print(r.bitop("AND","new","foo","foo1")) # "new" 0 0110000
print(r.mget("foo","foo1","new"))
source = "12"
for i in source:
num = ord(i)
print(num) # Вывести значение ASCII-кода, соответствующее каждому буквенному символу или китайскому иероглифу f-102-0b100111-01100111
print(bin(num)) # Вывести каждое десятичное значение ASCII-кода, преобразованное в двоичное значение 0b1100110 (0b обозначает двоичное)
print bin(num).replace('b','') # Заменить двоичное 0b1100110 на 01100110
17.strlen(name)
Возвращает длину в байтах значения, соответствующего name (один китайский иероглиф — 3 байта)
print(r.strlen("foo")) # 4 'goo1'的长度是4
18.incr(self, name, amount=1)
Увеличивает значение, соответствующее name. Если name не существует, создаёт name=amount, иначе увеличивает.
Параметры:
- name — имя в Redis
- amount — значение приращения (должно быть целым числом)
Примечание: то же самое, что incrby
Пример
print(r.mget("foo", "foo1", "foo2", "k1", "k2"))
r.incr("foo", amount=1)
print(r.mget("foo", "foo1", "foo2", "k1", "k2"))
Сценарий применения — подсчёт посещений страницы
Предположим, нам нужно записывать количество кликов для ряда страниц. Например, для каждого сообщения на форуме нужно записывать количество кликов, и количество кликов намного больше количества ответов. Если для хранения кликов используется реляционная база данных, может возникнуть большая конкуренция за блокировки на уровне строк. Поэтому использование команды INCR в redis для увеличения количества кликов является наилучшим.
При запуске сервера redis начальное значение счётчика кликов можно прочитать из реляционной базы данных (страница 12306 была посещена 34634 раза)
print(r.get("visit:12306:totals"))
При каждом клике по странице используйте INCR для увеличения количества кликов.
r.incr("visit:12306:totals")
При загрузке страницы это значение можно получить напрямую
print(r.get("visit:12306:totals"))
19.incrbyfloat(self, name, amount=1.0)
Увеличивает значение, соответствующее name. Если name не существует, создаёт name=amount, иначе увеличивает.
Параметры:
- name — имя в Redis
- amount — значение приращения (с плавающей запятой)
Пример
r.set("foo2", "221.0")
print(r.mget("foo1", "foo2"))
r.incrbyfloat("foo1", amount=2.0)
r.incrbyfloat("foo2", amount=3.0)
print(r.mget("foo1", "foo2"))
20.decr(self, name, amount=1)
Уменьшает значение, соответствующее name. Если name не существует, создаётся name=amount, иначе значение уменьшается.
Параметры:
- name — имя в Redis
- amount — значение декремента (целое число)
Пример
r.decr("foo1", amount=1) # Уменьшить на 1
print(r.mget("foo1", "foo4"))
21.append(key, value)
Добавить содержимое к значению, соответствующему имени redis
Параметры:
- key - имя redis
- value - строка для добавления
Пример
print(r.mget("name"))
основные команды redis hash
1. Одиночное добавление/обновление (одиночное получение) - добавить, если не существует, изменить, если существует
hset(name, key, value)
Установить пару ключ-значение в хэше, соответствующем name (если не существует, создать; иначе изменить)
Параметры:
- name — имя в Redis
- key - ключ в хэше, соответствующем name
- value - значение в хэше, соответствующем name
Примечание: hsetnx(name, key, value) создаёт, когда текущий ключ не существует в хэше, соответствующем name (эквивалентно добавлению)
Пример
import time
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.hset("hash1", "k1", "v1")
r.hset("hash1", "k2", "v2")
print(r.hkeys("hash1")) # Получить все ключи в хеше
print(r.hget("hash1", "k1")) # Получить значение, соответствующее ключу хеша, отдельно
print(r.hmget("hash1", "k1", "k2")) # Получить значения, соответствующие нескольким ключам хеша
r.hsetnx("hash1", "k2", "v3") # Можно только создавать новые
print(r.hget("hash1", "k2"))
2. Пакетное добавление (получение)
hmset(name, mapping)
Пакетно установить пары ключ-значение в хеше, соответствующем name
Параметры:
- name — имя в Redis
- mapping — словарь, например: {'k1':'v1', 'k2': 'v2'}
e.g.:
Пример
hget(name,key)
В хеше, соответствующем name, получить значение по ключу
hmget(name, keys, *args)
В хеше, соответствующем name, получить значения нескольких ключей
Параметры:
- name — имя, соответствующее redis
- keys — коллекция ключей для получения, например: ['k1', 'k2', 'k3']
- *args — ключи для получения, например: k1,k2,k3
e.g.:
Пример
print(r.hmget("hash2", "k2", "k3")) # Пакетно получить значения, соответствующие key-k2 и k3 из "hash2" -- способ 1
print(r.hmget("hash2", ["k2", "k3"])) # Пакетно получить значения, соответствующие key-k2 и k3 из "hash2" -- способ 2
3. Получить все пары ключ-значение
hgetall(name)
Получить все ключи и значения хеша, соответствующего name
print(r.hgetall("hash1"))
4. Получить формат всех пар ключ-значение, длину хеша
hlen(name)
Получить количество пар ключ-значение в хеше, соответствующем name
print(r.hlen("hash1"))
5. Получить все ключи (аналогично получению всех ключей словаря)
hkeys(name)
Получить значения всех ключей в хэше, соответствующем name
print(r.hkeys("hash1"))
6. Получить все значения (аналогично получению всех значений словаря)
hvals(name)
Получить все значения в хэше, соответствующем name
print(r.hvals("hash1"))
7. Проверить, существует ли элемент (аналогично 'in' для словаря)
hexists(name, key)
Проверить, существует ли переданный текущий ключ в хэше, соответствующем name
Пример
print(r.hexists("hash1", "k1")) # True: существует
8. Удалить пару ключ-значение
hdel(name,*keys)
Удалить пару ключ-значение указанного ключа в хэше, соответствующем name
Пример
r.hset("hash1", "k2", "v222") # Изменить существующий ключ k2
r.hset("hash1", "k11", "v1") # Добавить новую пару ключ-значение k11
r.hdel("hash1", "k1") # Удалить одну пару ключ-значение
print(r.hgetall("hash1"))
9. Инкремент/декремент целого числа (для значения, соответствующего ключу, целого числа, увеличение на 1 или 2, либо на другое целое число; отрицательное значение означает уменьшение)
hincrby(name, key, amount=1)
Увеличить значение указанного ключа в хеше, соответствующем name; если он не существует, создать key=amount
Параметры:
- name — имя в redis
- key — ключ, соответствующий хешу
- amount — число автоинкремента (целое число)
Пример
r.hincrby("hash1", "k3", amount=-1)
print(r.hgetall("hash1"))
r.hincrby("hash1", "k4", amount=1) # Если он не существует, значение по умолчанию равно 1
print(r.hgetall("hash1"))
10. Инкремент/декремент числа с плавающей точкой (для значения, соответствующего ключу, числа с плавающей точкой, увеличение на 1.0 или 2.0, либо на другое число с плавающей точкой; отрицательное значение означает уменьшение)
hincrbyfloat(name, key, amount=1.0)
Увеличить значение указанного ключа в хеше, соответствующем name; если он не существует, создать key=amount
Параметры:
- name — имя в redis
- key — ключ, соответствующий хешу
- amount, число автоинкремента (float)
Увеличивает значение указанного ключа в хеше, соответствующем name; если он не существует, создаёт key=amount.
Пример
r.hincrbyfloat("hash1", "k5", amount=-1.0) # Уже существует, уменьшение на -1.0
print(r.hgetall("hash1"))
r.hincrbyfloat("hash1", "k6", amount=-1.0) # Не существует, значение инициализируется -1.0, уменьшение на 1.0 каждый раз
print(r.hgetall("hash1"))
11. Получение значения — чтение по срезам
hscan(name, cursor=0, match=None, count=None)
Инкрементальная итеративная выборка очень полезна для больших данных. hscan может извлекать данные по шардам, а не извлекать все данные сразу, что предотвращает исчерпание памяти.
Параметры:
- name — имя в redis
- cursor — курсор (извлечение данных пакетами на основе курсора)
- match — сопоставление с указанным ключом, по умолчанию None означает все ключи
- count — минимальное число, извлекаемое на один шард, по умолчанию None означает использовать стандартное число шардов Redis
Например:
第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None)
第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None)
...
Пока возвращаемое значение курсора не равно 0, это означает, что все данные были получены с помощью шардинга
print(r.hscan("hash1"))
12, hscan_iter(name, match=None, count=None)
Используйте yield, чтобы обернуть hscan и создать генератор, позволяющий пакетно извлекать данные из redis
Параметры:
- match — сопоставление с указанным ключом, по умолчанию None означает все ключи
- count — минимальное число, извлекаемое на один шард, по умолчанию None означает использовать стандартное число шардов Redis
Например:
Пример
print(item)
print(r.hscan_iter("hash1")) # Адрес памяти генератора
5. Список базовых команд Redis
1. Добавить (аналогично append для списка, но здесь добавляет слева) -- создаёт новый, если он не существует
lpush(name,values)
Добавляет элемент в список, соответствующий name; каждый новый элемент добавляется в начало списка слева
Например:
Пример
import time
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.lpush("list1", 11, 22, 33)
print(r.lrange('list1', 0, -1))
Сохранённый порядок: 33, 22, 11
Дополнительно:
r.rpush("list2", 11, 22, 33) # 表示从右向左操作
print(r.llen("list2")) # 列表长度
print(r.lrange("list2", 0, 3)) # 切片取出值,范围是索引号0-3
2. Добавить (добавляет справа) -- создаёт новый, если он не существует
Пример
print(r.llen("list2")) # Длина списка
print(r.lrange("list2", 0, -1)) # Срез для получения значений, диапазон — от индекса 0 до -1 (последний элемент)
3. Добавить элемент в левую часть списка для существующего имени; если оно не существует, его нельзя создать
lpushx(name,value)
Добавить элемент в список, соответствующий name; только когда name уже существует, значение добавляется в самый левый край списка
Далее:
Пример
print(r.llen("list10")) # 0
print(r.lrange("list10", 0, -1)) # []
r.lpushx("list2", 77) # Здесь "list2" уже существовал раньше, добавьте элемент в самый левый край списка, только по одному за раз
print(r.llen("list2")) # Длина списка
print(r.lrange("list2", 0, -1)) # Срез для получения значений, диапазон — от индекса 0 до -1 (последний элемент
4. Добавить элемент в правую часть списка для существующего имени; если оно не существует, его нельзя создать
Пример
print(r.llen("list2")) # Длина списка
print(r.lrange("list2", 0, -1)) # Срез для получения значений, диапазон — от индекса 0 до -1 (последний элемент)
5. Добавить (вставить элемент в фиксированную позицию индекса)
linsert(name, where, refvalue, value))
Вставить новое значение до или после определённого значения в списке, соответствующем name
Параметры:
- name — имя в redis
- where - BEFORE или AFTER
- refvalue - опорное значение, то есть вставить данные до или после него
- value - данные для вставки
Пример
print(r.lrange("list2", 0, -1)) # Срез для получения значений, диапазон — от индекса 0 до последнего элемента
6. Изменить (изменение с указанием индекса)
r.lset(name, index, value)
Переприсвоить значение в определённой позиции индекса в списке, соответствующем name
Параметры:
- name — имя в redis
- index - позиция индекса в списке
- value — значение для установки
Пример
print(r.lrange("list2", 0, -1))
7. Удалить (удаление по указанному значению)
r.lrem(name, value, num)
Удалить указанное значение в списке, соответствующем name
Параметры:
- name — имя в redis
- value - значение для удаления
- num - num=0, удалить все указанные значения в списке;
- num=2 - удалить 2 от начала к концу; num=1, удалить первый слева при проходе от начала к концу
- num=-2 - удалить 2 от конца к началу
Пример
print(r.lrange("list2", 0, -1))
r.lrem("list2", "99", -1) # Удалить первое вхождение "99" справа в списке
print(r.lrange("list2", 0, -1))
r.lrem("list2", "22", 0) # Удалить все "22" в списке
print(r.lrange("list2", 0, -1))
8. Удалить и вернуть
lpop(name)
Получить первый элемент с левой стороны списка, соответствующего name, и удалить его из списка; возвращаемое значение - первый элемент
Далее:
rpop(name) означает операцию справа налево
Пример
print(r.lrange("list2", 0, -1))
r.rpop("list2") # Удалить самый правый элемент списка и вернуть удалённый элемент
print(r.lrange("list2", 0, -1))
9. Удалить значения вне диапазона индексов
ltrim(name, start, end)
В списке, соответствующем name, удалить значения, которые не находятся между индексами start и end
Параметры:
- name — имя в redis
- start — начальная позиция индекса
- end — конечная позиция индекса
Пример
print(r.lrange("list2", 0, -1))
10. Получить значение (получить значение по индексу)
lindex(name, index)
Получить элемент списка по индексу в списке, соответствующем name
print(r.lindex("list2", 0)) # 取出索引号是0的值
11. Переместить элемент из одного списка в другой список
rpoplpush(src, dst)
Взять самый правый элемент из одного списка и добавить его в крайнюю левую часть другого списка
Параметры:
- src — имя списка, из которого нужно взять данные
- dst — имя списка, в который нужно добавить данные
r.rpoplpush("list1", "list2")
print(r.lrange("list2", 0, -1))
12. Переместить элемент из одного списка в другой список с поддержкой таймаута
brpoplpush(src, dst, timeout=0)
Удалить элемент с правой стороны одного списка и добавить его в левую сторону другого списка
Параметры:
- src - имя списка, из которого нужно взять и удалить элемент
- dst - имя списка, в который нужно вставить элемент
- timeout - когда в списке, соответствующем src, нет данных, таймаут (в секундах) для блокировки до появления данных; 0 означает блокировку навсегда
Пример
print(r.lrange("list2", 0, -1))
13. Удалить из нескольких списков одновременно
blpop(keys, timeout)
Расположить несколько списков и извлекать элементы из соответствующих списков слева направо
Параметры:
- keys - коллекция имён redis
- timeout - период таймаута; после извлечения элементов из всех списков — время (в секундах) блокировки в ожидании данных в списке; 0 означает блокировку навсегда
Далее:
r.brpop(keys, timeout)То же, что и blpop, расположить несколько списков и удалять элементы из каждого списка справа налево
Пример
r.lpush("list11", 3, 4, 5)
while True:
r.blpop(["list10", "list11"], timeout=2)
print(r.lrange("list10", 0, -1), r.lrange("list11", 0, -1))
14. Пользовательская инкрементальная итерация
Поскольку библиотека redis не предоставляет инкрементальную итерацию по элементам списка, если вы хотите перебрать все элементы списка, соответствующего name, вам нужно получить весь список, соответствующий name.
Перебор списка
Однако, если список очень большой, это может исчерпать память программы на первом шаге, поэтому необходимо определить пользовательскую функцию инкрементальной итерации:
Пример
"""
Пользовательская инкрементальная итерация списка redis
:param name: имя в redis, т.е. итерация по списку, соответствующему name
:return: yield возвращает элементы списка
"""
list_count = r.llen(name)
for index in range(list_count):
yield r.lindex(name, index)
# Использование
for item in list_iter('list2'): # Пройти по этому списку
print(item)
6. Основные команды Redis set
1. Добавить
sadd(name,values)
name - добавить элементы в соответствующее множество
Пример
print(r.scard("set1")) # Длина множества равна 4
print(r.smembers("set1")) # Получить все элементы множества
2. Получить количество элементов, аналогично len
scard(name)
Получить количество элементов в множестве, соответствующем name
print(r.scard("set1")) # 集合的长度是4
3. Получить все элементы множества
smembers(name)
Получить все элементы множества, соответствующего имени
print(r.smembers("set1")) # 获取集合中所有的成员
Получить все элементы множества — в виде кортежа
sscan(name, cursor=0, match=None, count=None)
Пример:
print(r.sscan("set1"))
Получить все элементы множества — метод-итератор
sscan_iter(name, match=None, count=None)
Похоже на операции со строками, используется для инкрементальной итерации для извлечения элементов пакетами, избегая чрезмерного потребления памяти
for i in r.sscan_iter("set1"):
print(i)
4. Разность
sdiff(keys, *args)
Множество элементов, которые находятся в множестве, соответствующем первому имени, но отсутствуют в множествах, соответствующих другим именам
Пример
print(r.smembers("set1")) # Получить все элементы множества
print(r.smembers("set2"))
print(r.sdiff("set1", "set2")) # В set1, но не в set2
print(r.sdiff("set2", "set1")) # В set2, но не в set1
5. Разность — сохранить разность в новом множестве
sdiffstore(dest, keys, *args)
Получить элементы в множестве, соответствующем первому имени, но не в множествах, соответствующих другим именам, затем добавить их в множество, соответствующее dest
Пример
print(r.smembers("set3")) # Получить все элементы в set3
6. Пересечение
sinter(keys, *args)
Получить пересечение множеств, соответствующих нескольким именам
print(r.sinter("set1", "set2")) # 取2个集合的交集
7. Пересечение - сохранить пересечение в новом множестве
sinterstore(dest, keys, *args)
Получить объединение множеств, соответствующих нескольким именам, затем добавить его в множество, соответствующее dest
print(r.sinterstore("set3", "set1", "set2")) # 取2个集合的交集
print(r.smembers("set3"))
Объединение
sunion(keys, *args)
Получить объединение множеств, соответствующих нескольким именам
print(r.sunion("set1", "set2")) # 取2个集合的并集
Объединение - сохранить объединение в новом множестве
sunionstore(dest,keys, *args)
Получить объединение множеств, соответствующих нескольким именам, и сохранить результат в множество, соответствующее dest
print(r.sunionstore("set3", "set1", "set2")) # 取2个集合的并集
print(r.smembers("set3"))
8. Проверить, является ли он элементом множества, аналогично "in"
sismember(name, value)
Проверить, является ли value элементом множества, соответствующего name; результат — True или False
print(r.sismember("set1", 33)) # 33是集合的成员
print(r.sismember("set1", 23)) # 23不是集合的成员
9. Перемещение
smove(src, dst, value)
Переместить элемент из одного множества в другое множество
r.smove("set1", "set2", 44)
print(r.smembers("set1"))
print(r.smembers("set2"))
10. Удаление - случайное удаление и возврат удалённого значения
spop(name)
Удалить элемент из множества и вернуть его. Примечание: множество неупорядочено, поэтому удаляется случайный элемент.
print(r.spop("set2")) # 这个删除的值是随机删除的,集合是无序的
print(r.smembers("set2"))
11. Удаление - удаление по заданному значению
srem(name, values)
Удалить определённые значения из множества, соответствующего name
print(r.srem("set2", 11)) # 从集合中删除指定值 11
print(r.smembers("set2"))
7. Основные команды Redis для упорядоченного множества
Операции над множествами: множество — это список, не допускающий дубликатов и по своей природе неупорядоченный.
Упорядоченное множество: в основе лежит множество, каждый элемент сортируется; сортировка требует сравнения по другому значению. Поэтому в упорядоченном множестве каждый элемент имеет два значения: value и score. score специально используется для сортировки.
1. Добавить
zadd(name, *args, **kwargs)
Добавить элементы в упорядоченное множество, соответствующее name
Например:
Пример
import time
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.zadd("zset1", n1=11, n2=22)
r.zadd("zset2", 'm1', 22, 'm2', 44)
print(r.zcard("zset1")) # Длина множества
print(r.zcard("zset2")) # Длина множества
print(r.zrange("zset1", 0, -1)) # Получить все элементы упорядоченного множества
print(r.zrange("zset2", 0, -1, withscores=True)) # Получить все элементы и оценки в упорядоченном множестве
2. Получить количество элементов в упорядоченном множестве, аналогично len
zcard(name)
Получить количество элементов в упорядоченном множестве, соответствующем name
print(r.zcard("zset1")) # 集合长度
3. Получить все элементы упорядоченного множества
r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)
Получить элементы упорядоченного множества, соответствующего name, по диапазону индексов
Параметры:
- name — имя в redis
- start — начальная позиция индекса упорядоченного множества (не по оценке)
- end — конечная позиция индекса упорядоченного множества (не по оценке)
- desc — правило сортировки, по умолчанию сортировка по оценке от меньшей к большей
- withscores - получать ли оценку элемента; по умолчанию извлекается только значение элемента
- score_cast_func - функция преобразования данных оценки
3-1 Сортировка по убыванию (то же, что и zrange, множество сортируется по убыванию)
zrevrange(name, start, end, withscores=False, score_cast_func=float)
Пример
print(r.zrevrange("zset1", 0, -1)) # 只获取元素,不显示分数
print(r.zrevrange("zset1", 0, -1, withscores=True)) # 获取有序集合中所有元素和分数,分数倒序
3-2 Получить элементы упорядоченного множества, соответствующего name, по диапазону оценок
zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float)
Пример
Пример
element = 'n' + str(i)
r.zadd("zset3", element, i)
print(r.zrangebyscore("zset3", 15, 25)) # # Получить элементы, удовлетворяющие условию, с оценками в диапазоне 15-25
print(r.zrangebyscore("zset3", 12, 22, withscores=True)) # Получить элементы, удовлетворяющие условию, с оценками в диапазоне 12-22 (с оценками)
3-3 Получить элементы упорядоченного множества по диапазону оценок и отсортировать их (по умолчанию по убыванию)
zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float)
Пример
print(r.zrevrangebyscore("zset3", 22, 11, withscores=True)) # 在分数是22-11之间,取出符合条件的元素 按照Оценки в обратном порядке3-4 Получить все элементы — по умолчанию отсортированы по score
zscan(name, cursor=0, match=None, count=None, score_cast_func=float)
Пример
print(r.zscan("zset3"))
3-5 Получить все элементы — итератор
zscan_iter(name, match=None, count=None,score_cast_func=float)
Пример
for i in r.zscan_iter("zset3"): # 遍历迭代器
print(i)
4.zcount(name, min, max)
Получить количество score в упорядоченном множестве, соответствующем name, которые находятся в диапазоне [min, max]
print(r.zrange("zset3", 0, -1, withscores=True))
print(r.zcount("zset3", 11, 22))
5. Инкремент
zincrby(name, value, amount)
Увеличить score, соответствующий value, в упорядоченном множестве, соответствующем name
r.zincrby("zset3", "n2", amount=2) # 每次将n2的分数自增2
print(r.zrange("zset3", 0, -1, withscores=True))
6. Получить индекс значения
zrank(name, value)
Получить индекс определённого значения в упорядоченном множестве, соответствующем name (начиная с 0)
Далее:
zrevrank(name, value), отсортировано от наибольшего к наименьшему.
Пример
print(r.zrank("zset3", "n6")) # индекс n6 равен 1
print(r.zrevrank("zset3", "n1")) # индекс n1 равен 29, здесь в обратном порядке score (от большего к меньшему)
7. Удаление - удаление по указанному значению
zrem(name, values)
Удалить элементы, значения которых входят в упорядоченное множество, соответствующее имени
r.zrem("zset3", "n3") # 删除有序集合中的元素n3 删除单个
print(r.zrange("zset3", 0, -1))
8. Удаление - удаление по диапазону рангов, по номеру индекса
zremrangebyrank(name, min, max)
Удалить по диапазону рангов
r.zremrangebyrank("zset3", 0, 1) # 删除有序集合中的索引号是0, 1的元素
print(r.zrange("zset3", 0, -1))
9. Удаление - удаление по диапазону оценок
zremrangebyscore(name, min, max)
Удалить по диапазону оценок
r.zremrangebyscore("zset3", 11, 22) # 删除有序集合中的分数是11-22的元素
print(r.zrange("zset3", 0, -1))
10. Получить оценку, соответствующую значению
zscore(name, value)
Получить оценку, соответствующую значению в упорядоченном множестве, соответствующем имени
print(r.zscore("zset3", "n27")) # 获取元素n27对应的分数27
8. Другие распространённые операции
1. Удаление
delete(*names)
Удалить любой тип данных в Redis по имени (строка, хэш, список, множество, упорядоченное множество)
r.delete("gender") # 删除key为gender的键值对
2. Проверить, существует ли имя
exists(name)
Проверить, существует ли имя в Redis; True, если оно существует, False, если нет
print(r.exists("zset1"))
3. Нечёткое сопоставление
keys(pattern='')
Получить имена Redis по шаблону
Далее:
- KEYS * соответствует всем ключам в базе данных.
- KEYS h?llo соответствует hello, hallo, hxllo и т.д.
- KEYS hllo соответствует hllo и heeeeello и т.д.
- KEYS h[ae]llo соответствует hello и hallo, но не hillo
print(r.keys("foo*"))
4. Установить таймаут
expire(name ,time)
Установить таймаут для имени в Redis
r.lpush("list5", 11, 22)
r.expire("list5", time=3)
print(r.lrange("list5", 0, -1))
time.sleep(3)
print(r.lrange("list5", 0, -1))
5. Переименовать
rename(src, dst)
Переименовать имя в Redis
r.lpush("list5", 11, 22)
r.rename("list5", "list5-1")
6. Получить случайное имя
randomkey()
Получить случайное имя из Redis (без удаления)
print(r.randomkey())
7. Получить тип
type(name)
Получить тип значения, соответствующего name
print(r.type("set1"))
print(r.type("hash2"))
8. Просмотреть все элементы
Пример
print(r.hscan("hash2"))
print(r.sscan("set3"))
print(r.zscan("zset2"))
print(r.getrange("foo1", 0, -1))
print(r.lrange("list2", 0, -1))
print(r.smembers("set3"))
print(r.zrange("zset3", 0, -1))
print(r.hgetall("hash1"))
9. Просмотреть все элементы - итератор
Пример
for i in r.hscan_iter("hash1"):
print(i)
for i in r.sscan_iter("set3"):
print(i)
for i in r.zscan_iter("zset3"):
print(i)
другие методы
Пример
r.delete("gender") # Удалить пару ключ-значение с ключом gender
print(r.keys()) # Запросить все ключи
print(r.dbsize()) # Сколько элементов данных содержит текущий Redis
r.save() # Выполнить операцию "checkpoint" для записи данных обратно на диск. Блокирует во время сохранения.
# r.flushdb() # Очистить все данные в r
Конвейер (pipeline)
По умолчанию redis создает и разрывает соединение для каждого запроса (запрашивая соединение из пула соединений и возвращая его в пул). Если вы хотите указать несколько команд в одном запросе, можно использовать pipeline для выполнения нескольких команд в одном запросе; по умолчанию pipeline является атомарной операцией.
Pipeline — это подкласс базового класса, который redis предоставляет для буферизации нескольких серверных команд в одном запросе. Он значительно улучшает функциональность выполнения пакетных команд за счет сокращения повторяющихся TCP-пакетов между сервером и клиентом.
Пример
import time
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
# pipe = r.pipeline(transaction=False) # По умолчанию команды, выполняемые в pipeline, обеспечивают атомарность; выполнение pipe = r.pipeline(transaction=False) отключает эту возможность.
# pipe = r.pipeline(transaction=True)
pipe = r.pipeline() # Создать pipeline
pipe.set('name', 'jack')
pipe.set('role', 'sb')
pipe.sadd('faz', 'baz')
pipe.incr('num') # Если num не существует, значение равно 1; если существует, значение увеличивается на 1
pipe.execute()
print(r.get("name"))
print(r.get("role"))
print(r.get("num"))
Команды конвейера можно записывать вместе, например:
Пример
print(r.get("name"))
print(r.get("role"))
print(r.get("num"))
Автор: Junxi丶