この章では、Python で redis を操作する方法を紹介します。redis は Key-Value データベースであり、Value は string(文字列)、list(リスト)、set(集合)、zset(ソート済み集合)、hash(ハッシュ型)などの型をサポートしています。

redis の詳細については、私たちのredis チュートリアル、この章を学習する前に、redis サービスがインストールされていることを確認してください。

redis 起動画面は次のとおりです:

redis を起動

$ ./redis-server
75858:C 25 Oct 11:43:34.329 # Warning: no config file specified, using the default config. In order to specify a config file use ./redis-server /path/to/redis.conf
75858:M 25 Oct 11:43:34.331 * Increased maximum number of open files to 10032 (it was originally set to 256).
                _._                                                  
           _.-``__ ''-._                                            
      _.-``    `.  `_.  ''-._           Redis 3.0.3 (255fcb1a/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                  
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'
` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'
   |     PID: 75858
  `-._    `-._  `-./  _.-'    _.-'                                  
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'
_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'
_.-'    _.-'                                  
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'
_.-'    |                                  
  `-._    `-._`-.__.-'
_.-'    _.-'                                  
      `-._    `-.__.-'    _.-'                                      
          `-._        _.-'                                          
              `-.__.-'
                                             

75858:M 25 Oct 11:43:34.337 # Server started, Redis version 3.0.3
75858:M 25 Oct 11:43:34.339 * DB loaded from disk: 0.002 seconds
75858:M 25 Oct 11:43:34.339 * The server is now ready to accept connections on port 6379

デフォルトのポート番号は6379。


redis モジュールをインストール

Python で redis を使用するには、まず 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 の2つのクラスを提供します。StrictRedis は公式コマンドの大部分を実装するために使用され、Redis は StrictRedis のサブクラスで、旧バージョンとの後方互換性のために使用されます。

redis から取得される結果はデフォルトではバイト型です。設定できます。decode_responses=True文字列に変更します。

例

import redis   # redis モジュールをインポート

r = redis.Redis(host='localhost', port=6379, decode_responses=True)  
r.set('name', 'サンプル')  # name に対応する値を設定
print(r['name'])
print(r.get('name'))  # キー name に対応する値を取得
print(type(r.get('name')))  # 型を確認

出力結果は次のとおりです:

サンプル
サンプル
<class 'str'>

コネクションプール

redis-py は connection pool を使用して、1つの redis server へのすべての接続を管理し、接続の確立・解放のたびのオーバーヘッドを回避します。

デフォルトでは、各 Redis インスタンスは自身のコネクションプールを維持します。コネクションプールを直接作成し、それをパラメータとして Redis に渡すことで、複数の Redis インスタンスで1つのコネクションプールを共有できます。

例

import 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', 'サンプル')  # name に対応する値を設定
print(r.get('name'))  # キー name に対応する値を取得

redis 基本コマンド String

set(name, value, ex=None, px=None, nx=False, xx=False)

Redis で値を設定する場合、デフォルトでは、存在しなければ作成し、存在すれば変更します。

パラメータ:

  • ex - 有効期限(秒)
  • px - 有効期限(ミリ秒)
  • nx - Trueに設定すると、nameが存在しない場合にのみ、現在のset操作が実行されます
  • xx - Trueに設定すると、nameが存在する場合にのみ、現在のset操作が実行されます

1. ex - 有効期限(秒) ここでは有効期限は3秒です。3秒後、キー food の値は None になります。

例

import redis

pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)
r.set('food', 'mutton', ex=3)    # key は "food"、value は "mutton" で、キーと値のペアを redis キャッシュに保存します
print(r.get('food'))  # mutton キー food に対応する値を取得

2. px - 有効期限(ミリ秒) ここでは有効期限は3ミリ秒です。3ミリ秒後、キー foo の値は None になります。

例

import redis

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に設定すると、nameが存在しない場合にのみ、現在のset操作が実行されます(新規作成)

例

import redis

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に設定すると、nameが存在する場合にのみ、現在のset操作が実行されます(変更)

例

print((r.set('fruit', 'watermelon', xx=True)))   # True--すでに存在
# キー fruit がすでに存在すれば、出力は True;キー fruit が存在しなければ、出力は None

5.setnx(name, value)

値を設定します。nameが存在しない場合のみ、設定操作を実行します(追加)

print(r.setnx('fruit1', 'banana'))  # fruit1不存在,输出为True

6.setex(name, time, value)

値を設定

パラメータ:

time - 有効期限(数値の秒 または timedelta オブジェクト)

例

import redis
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 オブジェクト)

例

r.psetex("fruit3", 5000, "apple")
time.sleep(5)
print(r.get('fruit3'))  # 5000ミリ秒後、値は apple から None に変わります

8.mset(*args, **kwargs)

一括で値を設定

例:

例

r.mget({'k1': 'v1', 'k2': 'v2'})
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(['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 の name
  • start - 開始位置(バイト)
  • end - 終了位置(バイト)

例: "君惜大大" の場合、0-3 は "君" を表します

例

r.set("cn_name", "君惜大大") # 漢字
print(r.getrange("cn_name", 0, 2))   # インデックスが0-2の最初の3バイトを取得 君 スライス操作 (漢字1文字は3バイト、英字1文字は1バイト、各バイトは8bit)
print(r.getrange("cn_name", 0, -1))  # すべてのバイトを取得 君惜大大 スライス操作
r.set("en_name","junxi") # 英字
print(r.getrange("en_name", 0, 2))  # インデックスが0-2の最初の3バイトを取得 jun スライス操作 (漢字1文字は3バイト、英字1文字は1バイト、各バイトは8bit)
print(r.getrange("en_name", 0, -1)) # すべてのバイトを取得 junxi スライス操作

12.setrange(name, offset, value)

文字列の内容を変更し、指定した文字列インデックスから後ろを置換します(新しい値が長すぎる場合は、後ろに追加します)

パラメータ:

  • offset - 文字列のインデックス、バイト(漢字1文字は3バイト)
  • value - 設定する値

例

r.setrange("en_name", 1, "ccc")
print(r.get("en_name"))    # jccci 元の値はjunxi、インデックス番号1からcccに置換すると jccci になります

13.setbit(name, offset, value)

nameに対応する値のバイナリ表現のビットに対して操作します

パラメータ:

  • name - Redisのname
  • offset - ビットのインデックス(値をバイナリに変換してからインデックス付けします)
  • value - 値は1または0のみ

注:Redisに次のような対応がある場合: n1 = "foo"、

その場合、文字列fooのバイナリ表現は:01100110 01101111 01101111

したがって、setbit('n1', 7, 1) を実行すると、7ビット目が1に設定され、

その場合、最終的なバイナリは 01100111 01101111 01101111 となり、つまり:"goo" になります

拡張、バイナリ表現の変換:

例

source = "陈思维"
source = "foo"
for i in source:
num = ord(i)
print bin(num).replace('b','')

特に、sourceが漢字 "陈思维" の場合はどうしますか?

答:utf-8の場合、漢字1文字は3バイトを占めるため、"陈思维" は9バイトになります。 漢字の場合、forループはバイト単位で反復します。反復時に各バイトを10進数に変換し、その10進数を2進数に変換します。 11100110 10101101 10100110 11100110 10110010 10011011 11101001 10111101 10010000

14.getbit(name, offset)

nameに対応する値のバイナリ表現における特定のビットの値(0または1)を取得します

print(r.getbit("foo1", 0)) # 0 foo1 对应的二进制 4个字节 32位 第0位是0还是1

15.bitcount(key, start=None, end=None)

nameに対応する値のバイナリ表現における1の数を取得します

パラメータ:

  • key - Redisのname
  • start - バイトの開始位置
  • end - バイトの終了位置

例

print(r.get("foo"))  # goo1 01100111
print(r.bitcount("foo",0,1))  # 11 は先頭2バイトの中に1が出現する回数を示します

16.bitop(operation, dest, *keys)

複数の値を取得し、値に対してビット演算を行い、最後の結果を新しいnameに対応する値に保存します

パラメータ:

  • operation - AND(論理積)、OR(論理和)、NOT(否定)、XOR(排他的論理和)
  • dest - 新しいRedisのname
  • *keys - 検索するRedisのname

例:

bitop("AND", 'new_name', 'n1', 'n2', 'n3')

Redis内のn1,n2,n3に対応する値を取得し、すべての値に対してビット演算(論理和)を行い、結果をnew_nameに対応する値に保存します

例

r.set("foo","1")  # 0110001
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))  # 各10進数のASCIIコード値を2進数に変換した値を出力 0b1100110(0bは2進数を示す)
print bin(num).replace('b','')  # 2進数の0b1100110を01100110に置き換える

17.strlen(name)

nameに対応する値のバイト長を返します(漢字1文字は3バイト)

print(r.strlen("foo"))  # 4 'goo1'的长度是4

18.incr(self, name, amount=1)

nameに対応する値をインクリメントします。nameが存在しない場合は name=amount を作成し、存在する場合はインクリメントします。

パラメータ:

  • name - Redisのname
  • amount - インクリメント数(整数である必要があります)

注:incrby と同じ

例

r.set("foo", 123)
print(r.mget("foo", "foo1", "foo2", "k1", "k2"))
r.incr("foo", amount=1)
print(r.mget("foo", "foo1", "foo2", "k1", "k2"))

適用シナリオ – ページクリック数

一系列のページについてクリック数を記録する必要があると仮定します。例えばフォーラムの各投稿のクリック数を記録する必要があり、クリック数は返信数よりはるかに多くなります。リレーショナルデータベースを使用してクリック数を保存する場合、大量の行レベルのロック競合が発生する可能性があります。したがって、クリック数の増加にはredisのINCRコマンドを使用するのが最適です。

redisサーバー起動時に、リレーショナルデータベースからクリック数の初期値を読み込むことができます(12306というページは34634回アクセスされました)

r.set("visit:12306:totals", 34634)
print(r.get("visit:12306:totals"))

ページがクリックされるたびに、INCRを使用してクリック数を増やせばよいです。

r.incr("visit:12306:totals")
r.incr("visit:12306:totals")

ページ読み込み時にこの値を直接取得できます。

print(r.get("visit:12306:totals"))

19.incrbyfloat(self, name, amount=1.0)

nameに対応する値をインクリメントします。nameが存在しない場合は name=amount を作成し、存在する場合はインクリメントします。

パラメータ:

  • name - Redisのname
  • amount - インクリメント数(浮動小数点型)

例

r.set("foo1", "123.0")
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のname
  • amount - デクリメント数(整数)

例

r.decr("foo4", amount=3) # 3減算
r.decr("foo1", amount=1) # 1減算
print(r.mget("foo1", "foo4"))

21.append(key, value)

redisのnameに対応する値の後ろに内容を追加します

パラメータ:

  • key - redisのname
  • value - 追加する文字列

例

r.append("name", "haha")    # nameに対応する値junxiの後ろに文字列hahaを追加
print(r.mget("name"))

redis 基本コマンド hash

1、単一追加--変更(単一取得)--なければ新規追加、あれば変更

hset(name, key, value)

nameに対応するhashにキーと値のペアを設定します(存在しない場合は作成、存在する場合は修正)

パラメータ:

  • name - redisのname
  • key - nameに対応するhash内のキー
  • value - nameに対応するhash内のバリュー

注:hsetnx(name, key, value) は、nameに対応するhash内に現在のkeyが存在しない場合に作成します(追加に相当)

例

import redis
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")) # hash内のすべてのkeyを取得
print(r.hget("hash1", "k1"))    # hashのkeyに対応する値を単一で取得
print(r.hmget("hash1", "k1", "k2")) # hashのkeyに対応する値を複数で取得
r.hsetnx("hash1", "k2", "v3") # 新規作成のみ可能
print(r.hget("hash1", "k2"))

2、一括追加(取得)

hmset(name, mapping)

nameに対応するhash内にキーと値のペアを一括設定します

パラメータ:

  • name - redisのname
  • mapping - 辞書、例:{'k1':'v1', 'k2': 'v2'}

例:

例

r.hmset("hash2", {"k2": "v2", "k3": "v3"})
hget(name,key)

nameに対応するhash内でkeyに基づいてvalueを取得します

hmget(name, keys, *args)

nameに対応するhash内で複数のkeyの値を取得します

パラメータ:

  • name - reidsに対応するname
  • keys - 取得するkeyの集合、例:['k1', 'k2', 'k3']
  • *args - 取得するkey、例:k1,k2,k3

例:

例

print(r.hget("hash2", "k2"))  # "hash2"のkey-k2に対応するvalueを単一で取得
print(r.hmget("hash2", "k2", "k3"))  # "hash2"のkey-k2 k3に対応するvalueを一括取得 --方法1
print(r.hmget("hash2", ["k2", "k3"]))  # "hash2"のkey-k2 k3に対応するvalueを一括取得 --方法2

3、すべてのキーと値のペアを取得する

hgetall(name)

nameに対応するhashのすべてのキーと値を取得します

print(r.hgetall("hash1"))

4、すべてのキーと値のペアの個数(hash長さ)を取得する

hlen(name)

nameに対応するhash内のキーと値のペアの数を取得します

print(r.hlen("hash1"))

5、すべての keys を取得する(辞書の全キー取得と同様)

hkeys(name)

nameに対応するhash内のすべてのkeyを取得します

print(r.hkeys("hash1"))

6、すべての value を取得する(辞書の全バリュー取得と同様)

hvals(name)

nameに対応するhash内のすべてのvalueを取得します

print(r.hvals("hash1"))

7、メンバーが存在するかどうかを判断する(辞書の in と同様)

hexists(name, key)

nameに対応するhashに現在渡されたkeyが存在するかどうかを確認します

例

print(r.hexists("hash1", "k4"))  # False 存在しない
print(r.hexists("hash1", "k1"))  # True 存在する

8、キーと値のペアを削除する

hdel(name,*keys)

nameに対応するhash内の指定されたkeyのキーと値のペアを削除します

例

print(r.hgetall("hash1"))
r.hset("hash1", "k2", "v222")   # 既存のkey k2を修正
r.hset("hash1", "k11", "v1")   # キーと値のペア k11 を新規追加
r.hdel("hash1", "k1")    # 1つのキーと値のペアを削除
print(r.hgetall("hash1"))

9、整数のインクリメント・デクリメント(keyに対応するvalue(整数)を1または2、または他の整数だけインクリメント、負数ならデクリメント)

hincrby(name, key, amount=1)

nameに対応するhash内の指定されたkeyの値をインクリメントし、存在しない場合は key=amount を作成します

パラメータ:

  • name - redis内のname
  • key - hashに対応するkey
  • amount - 増分値(整数)

例

r.hset("hash1", "k3", 123)
r.hincrby("hash1", "k3", amount=-1)
print(r.hgetall("hash1"))
r.hincrby("hash1", "k4", amount=1)  # 存在しない場合、valueのデフォルトは1です
print(r.hgetall("hash1"))

10、浮動小数点数のインクリメント・デクリメント(keyに対応するvalue(浮動小数点数)を1.0または2.0、または他の浮動小数点数だけインクリメント、負数ならデクリメント)

hincrbyfloat(name, key, amount=1.0)

nameに対応するhash内の指定したkeyの値をインクリメントします。存在しない場合はkey=amountとして作成します

パラメータ:

  • name - redis内のname
  • key - hashに対応するkey
  • amount、増分値(浮動小数点数)

nameに対応するhash内の指定したkeyの値をインクリメントします。存在しない場合はkey=amountとして作成します。

例

r.hset("hash1", "k5", "1.0")
r.hincrbyfloat("hash1", "k5", amount=-1.0)    # すでに存在する場合、-1.0ずつデクリメント
print(r.hgetall("hash1"))
r.hincrbyfloat("hash1", "k6", amount=-1.0)    # 存在しない場合、valueの初期値は-1.0で、毎回1.0ずつデクリメント
print(r.hgetall("hash1"))

11、値の取得・確認--スライス読み取り

hscan(name, cursor=0, match=None, count=None)

インクリメンタルな反復取得は、データ量が多い場合に非常に役立ちます。hscanは分割でのデータ取得を実現でき、一度にすべてのデータを取得するわけではないため、メモリが圧迫されることを防げます

パラメータ:

  • name - redis内のname
  • cursor - カーソル(カーソルに基づいてデータをバッチで取得)
  • match - 指定したkeyにマッチ。デフォルトはNoneで、すべてのkeyを意味します
  • 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)
...

戻り値のcursorの値が0になった時点で、データが分割で取得し終えたことを意味します

print(r.hscan("hash1"))

12、hscan_iter(name, match=None, count=None)

yieldを使ってhscanをラップしジェネレータを作成することで、redisからデータを分割で取得することを実現します

パラメータ:

  • match - 指定したkeyにマッチ。デフォルトはNoneで、すべてのkeyを意味します
  • count - 各分割で最低限取得する件数。デフォルトはNoneで、Redisのデフォルトの分割件数を使用します

例:

例

for item in r.hscan_iter('hash1'):
    print(item)
print(r.hscan_iter("hash1"))    # ジェネレータのメモリアドレス

5、redis 基本コマンド list

1.追加(listのappendに似ていますが、ここでは左から新しく追加します)--存在しなければ新規作成

lpush(name,values)

nameに対応するlistに要素を追加します。各新しい要素はリストの一番左に追加されます

例:

例

import redis
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.追加(右から追加)--存在しなければ新規作成

例

r.rpush("list2", 44, 55, 66)    # リストの右側に、順に44,55,66を追加
print(r.llen("list2"))  # リストの長さ
print(r.lrange("list2", 0, -1)) # スライスで値を取得、範囲はインデックス0から-1(最後の要素)

3.既存のnameのリストの左側に要素を追加します。存在しない場合は作成できません

lpushx(name,value)

nameに対応するlistに要素を追加します。nameがすでに存在する場合のみ、値はリストの一番左に追加されます

詳細:

例

r.lpushx("list10", 10)   # ここではlist10は存在しません
print(r.llen("list10"))  # 0
print(r.lrange("list10", 0, -1))  # []
r.lpushx("list2", 77)   # ここでは"list2"はすでに存在しているので、リストの一番左に要素を1つ追加します。一度に追加できるのは1つのみです
print(r.llen("list2"))  # リストの長さ
print(r.lrange("list2", 0, -1)) # スライスで値を取得、範囲はインデックス0から-1(最後の要素

4.既存のnameのリストの右側に要素を追加します。存在しない場合は作成できません

例

r.rpushx("list2", 99)   # ここでは"foo_list1"はすでに存在しているので、リストの一番右に要素を1つ追加します。一度に追加できるのは1つのみです
print(r.llen("list2"))  # リストの長さ
print(r.lrange("list2", 0, -1)) # スライスで値を取得、範囲はインデックス0から-1(最後の要素)

5.新規追加(固定のインデックス位置に要素を挿入)

linsert(name, where, refvalue, value))

nameに対応するリスト内の特定の値の前または後ろに新しい値を挿入します

パラメータ:

  • name - redis内のname
  • where - BEFOREまたはAFTER
  • refvalue - 基準値、つまり、その前後にデータを挿入します
  • value - 挿入するデータ

例

r.linsert("list2", "before", "11", "00")   # リスト内で左側から最初に出現する要素"11"の前に要素"00"を挿入
print(r.lrange("list2", 0, -1))   # スライスで値を取得、範囲はインデックス0から最後の要素

6.修正(指定したインデックスで修正)

r.lset(name, index, value)

nameに対応するlist内の特定のインデックス位置に再代入します

パラメータ:

  • name - redis内のname
  • index - listのインデックス位置
  • value - 設定する値

例

r.lset("list2", 0, -11)    # インデックスが0の要素を-11に変更
print(r.lrange("list2", 0, -1))

7.削除(指定した値で削除)

r.lrem(name, value, num)

nameに対応するlist内の指定した値を削除します

パラメータ:

  • name - redis内のname
  • value - 削除する値
  • num - num=0、リスト内の指定した値をすべて削除;
  • num=2 - 前から後ろへ、2つ削除。num=1、前から後ろへ、左から1つ目を削除
  • num=-2 - 後ろから前へ、2つ削除

例

r.lrem("list2", "11", 1)    # リスト内で左側から最初に出現する"11"を削除
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) は右から左への操作を表します

例

r.lpop("list2")    # リストの一番左の要素を削除し、削除した要素を返す
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内のname
  • start - インデックスの開始位置
  • end - インデックスの終了位置

例

r.ltrim("list2", 0, 2)    # インデックスが0-2の範囲外の要素を削除し、インデックスが0-2の要素を保持
print(r.lrange("list2", 0, -1))

10.値の取得(インデックスに基づいて値を取得)

lindex(name, index)

nameに対応するリスト内で、インデックスに基づいてリスト要素を取得します

print(r.lindex("list2", 0))  # 取出索引号是0的值

11.移動 要素をあるリストから別のリストへ移動

rpoplpush(src, dst)

あるリストから一番右の要素を取り出し、同時にそれを別のリストの一番左に追加します

パラメータ:

  • src - データを取得するリストのname
  • dst - データを追加するリストのname
r.rpoplpush("list1", "list2")
print(r.lrange("list2", 0, -1))

12.移動 要素をあるリストから別のリストへ移動 タイムアウトを設定可能

brpoplpush(src, dst, timeout=0)

あるリストの右側から要素を1つ削除し、それを別のリストの左側に追加します

パラメータ:

  • src - 要素を取り出して削除するリストに対応するname
  • dst - 要素を挿入するリストに対応するname
  • timeout - srcに対応するリストにデータがない場合、データができるまでブロックして待機するタイムアウト時間(秒)。0 は永遠にブロックすることを意味します

例

r.brpoplpush("list1", "list2", timeout=2)
print(r.lrange("list2", 0, -1))

13.複数のリストからの一括削除

blpop(keys, timeout)

複数のリストを並べて、左から右へ対応するリストの要素をpopします

パラメータ:

  • keys - redisのnameの集合
  • timeout - タイムアウト時間。すべてのリストの要素を取得し終えた後、リスト内にデータができるまでブロックして待機する時間(秒)。0 は永遠にブロックすることを意味します

詳細:

r.brpop(keys, timeout)blpopと同じく、複数のリストを並べ、右から左へ各リスト内の要素を削除します

例

r.lpush("list10", 3, 4, 5)
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に対応するすべてのリストを取得する必要があります。

リストをループ

しかし、リストが非常に大きい場合、最初のステップでプログラムのメモリを圧迫する可能性があります。そのため、カスタムの増分反復機能を定義する必要があります:

例

def list_iter(name):
    """
redisリストのカスタム・増分反復
:param name: redis内のname、つまり: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 - 対応する集合に要素を追加します

例

r.sadd("set1", 33, 44, 55, 66)  # 集合に要素を追加
print(r.scard("set1"))  # 集合の長さは4
print(r.smembers("set1"))   # 集合内のすべてのメンバーを取得

2. 要素数の取得 lenと同様

scard(name)

nameに対応する集合内の要素数を取得

print(r.scard("set1"))  # 集合的长度是4

3. 集合内のすべてのメンバーを取得

smembers(name)

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)

最初のnameに対応する集合には存在するが、他のnameに対応する集合には存在しない要素の集合

例

r.sadd("set2", 11, 22, 33)
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)

最初のnameに対応する集合には存在するが他のnameに対応する集合には存在しない要素を取得し、それをdestに対応する集合に新たに追加します。

例

r.sdiffstore("set3", "set1", "set2")    # 集合set1にはあるが、集合set2にはない
print(r.smembers("set3"))   # 集合3のすべてのメンバーを取得

6. 積集合

sinter(keys, *args)

複数のnameに対応する集合の積集合を取得

print(r.sinter("set1", "set2")) # 取2个集合的交集

7. 積集合--積集合を新しい集合に保存

sinterstore(dest, keys, *args)

複数のnameに対応する集合の和集合を取得し、それをdestに対応する集合に追加します。

print(r.sinterstore("set3", "set1", "set2")) # 取2个集合的交集
print(r.smembers("set3"))

和集合

sunion(keys, *args)

複数のnameに対応する集合の和集合を取得

print(r.sunion("set1", "set2")) # 取2个集合的并集

和集合--和集合を新しい集合に保存

sunionstore(dest,keys, *args)

複数のnameに対応する集合の和集合を取得し、結果を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)

集合からメンバーを1つ削除し、それを返します。補足すると、集合は順序がないため、ランダムに削除されます。

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 基本コマンド ソート済みset(sorted set)

Set操作。Set集合は重複を許可しないリストであり、それ自体は順序がありません。

順序付き集合は、集合を基に各要素を並べ替えます。要素の並べ替えは別の値を使って比較する必要があるため、順序付き集合では各要素に値とスコアの2つの値があり、スコアは専ら並べ替えに使用されます。

1. 追加

zadd(name, *args, **kwargs)

nameに対応する順序付き集合に要素を追加

例:

例

import redis
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のname
  • 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)

例

例

for i in range(1, 30):
   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 すべての要素を取得--デフォルトではスコア順に並べ替え

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)

nameに対応する順序付き集合内でスコアが [min,max] の間にある要素の個数を取得

print(r.zrange("zset3", 0, -1, withscores=True))
print(r.zcount("zset3", 11, 22))

5. インクリメント

zincrby(name, value, amount)

nameに対応する順序付き集合の、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", "n1"))   # n1のインデックス番号は0 ここではスコア順(小さい順)
print(r.zrank("zset3", "n6"))   # n6のインデックス番号は1

print(r.zrevrank("zset3", "n1"))    # n1のインデックス番号は29 ここではスコアの降順(大きい順)

7. 削除--指定値の削除

zrem(name, values)

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)

nameに対応する順序付き集合内でvalueに対応するスコアを取得

print(r.zscore("zset3", "n27"))   # 获取元素n27对应的分数27

8、その他の一般的な操作

1. 削除

delete(*names)

redis内の任意のデータ型(string、hash、list、set、順序付きset)を削除

r.delete("gender")  # 删除key为gender的键值对

2. 名前の存在確認

exists(name)

redisのnameが存在するか確認。存在すればTrue、存在しなければFalse

print(r.exists("zset1"))

3. あいまい検索

keys(pattern='')

パターンに基づいてredisのnameを取得

詳細:

  • 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のあるnameにタイムアウト時間を設定

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のnameの名前を変更

r.lpush("list5", 11, 22)
r.rename("list5", "list5-1")

6. nameをランダムに取得

randomkey()

redisのnameをランダムに1つ取得(削除しない)

print(r.randomkey())

7. 型の取得

type(name)

nameに対応する値の型を取得

print(r.type("set1"))
print(r.type("hash2"))

8. すべての要素を表示

例

scan(cursor=0, match=None, count=None)

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. すべての要素を表示--イテレータ

例

scan_iter(match=None, count=None)

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)

other メソッド

例

print(r.get('name'))    # keyがnameである値を照会
r.delete("gender")  # keyがgenderであるキーと値のペアを削除
print(r.keys()) # すべてのキーを照会
print(r.dbsize())   # 現在のredisに含まれるデータの件数
r.save()    # 「チェックポイント」操作を実行し、データをディスクに書き戻します。保存時はブロックされます。
# r.flushdb() # r内のすべてのデータをクリア

パイプライン(pipeline)

redisはデフォルトで、各リクエストの実行時に接続の作成(接続プールから接続を取得)と切断(接続プールへ返却)という1回の接続操作を行います。1回のリクエストで複数のコマンドを指定したい場合は、pipelineを使用して1回のリクエストで複数のコマンドを指定でき、デフォルトでは1回のpipelineは原子性のある操作です。

パイプライン(pipeline)は、redisが単一のリクエスト内で複数のサーバーコマンドをバッファリングするための基本クラスのサブクラスです。サーバーとクライアント間で繰り返し送受信されるTCPデータパケットを減らすことで、バッチコマンドを実行する機能を大幅に向上させます。

例

import redis
import time

pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)

# pipe = r.pipeline(transaction=False) # デフォルトでは、パイプライン内で実行されるコマンドは実行の原子性が保証されます。pipe = r.pipeline(transaction=False)を実行するとこの特性を無効にできます。
# pipe = r.pipeline(transaction=True)
pipe = r.pipeline() # パイプラインを作成

pipe.set('name', 'jack')
pipe.set('role', 'sb')
pipe.sadd('faz', 'baz')
pipe.incr('num')    # numが存在しない場合vauleは1、存在する場合valueは1ずつインクリメント
pipe.execute()

print(r.get("name"))
print(r.get("role"))
print(r.get("num"))

パイプラインのコマンドはまとめて書くこともできます。例:

例

pipe.set('hello', 'redis').sadd('faz', 'baz').incr('num').execute()
print(r.get("name"))
print(r.get("role"))
print(r.get("num"))

作者:君惜丶

リンク:https://www.jianshu.com/p/2639549bedc8