redisを使用して辞書を保存および取得する方法


97
# I have the dictionary my_dict
my_dict = {
    'var1' : 5
    'var2' : 9
}
r = redis.StrictRedis()

my_dictを保存し、redisで取得するにはどうすればよいですか?たとえば、次のコードは機能しません。

#Code that doesn't work
r.set('this_dict', my_dict)  # to store my_dict in this_dict
r.get('this_dict')  # to retrieve my_dict

回答:


166

あなたはそれを行うことができますhmset(複数のキーはを使用して設定できますhmset)。

hmset("RedisKey", dictionaryToSet)

import redis
conn = redis.Redis('localhost')

user = {"Name":"Pradeep", "Company":"SCTL", "Address":"Mumbai", "Location":"RCP"}

conn.hmset("pythonDict", user)

conn.hgetall("pythonDict")

{'Company': 'SCTL', 'Address': 'Mumbai', 'Location': 'RCP', 'Name': 'Pradeep'}

51
単にdictではなくネストされたデータ構造である場合(たとえば、いくつかの配列などを含む場合)json.dumps()、文字列として書き込みを使用してデータをjson.loads()シリアル化し、Redisユーザーから取得してPythonデータ構造に逆シリアル化する
andilabs 2016

8
json.dumps()そしてjson.loads()、辞書のキーが常に文字列であることに問題がない場合にのみ機能します。そうでない場合は、ピクルスの使用を検討してください。
ryechus 2017

7
jsonはバイトと互換性がないため、jsonのセリリゼーションはグローバルなソリューションではありません。たとえば、バイト値を持つdictがある場合、これは機能しません。
トミー

9
ちなみに、のドキュメントにhmsetはこれは記載されていませんが、空のdictを保存しようとするとDataErrorが発生します。
hlongmore

2
@Pradeepキーを動的にする方法。データが15分ごとに挿入されると仮定して、キーを動的にする方法
ak3191 2018年

37

辞書をピクルスにして文字列として保存できます。

import pickle
import redis

r = redis.StrictRedis('localhost')
mydict = {1:2,2:3,3:4}
p_mydict = pickle.dumps(mydict)
r.set('mydict',p_mydict)

read_dict = r.get('mydict')
yourdict = pickle.loads(read_dict)

12
これは真実ですが、読み取りと書き込みの速度によっては、深刻なオーバーヘッドが追加される可能性があります。酸洗いは遅い操作です
トミー

2
これは、サーバがユーザの入力に使用されている場合がありますのでご注意くださいリモートでコード・実行しやすいpickle.loads100%のみを使用する必要がありますされ、データの信頼できる
Paradoxis

16

別の方法:RedisWorksライブラリを使用できます。

pip install redisworks

>>> from redisworks import Root
>>> root = Root()
>>> root.something = {1:"a", "b": {2: 2}}  # saves it as Hash type in Redis
...
>>> print(root.something)  # loads it from Redis
{'b': {2: 2}, 1: 'a'}
>>> root.something['b'][2]
2

PythonタイプをRedisタイプに、またはその逆に変換します。

>>> root.sides = [10, [1, 2]]  # saves it as list in Redis.
>>> print(root.sides)  # loads it from Redis
[10, [1, 2]]
>>> type(root.sides[1])
<class 'list'>

免責事項:私はライブラリを作成しました。コードは次のとおりです:https//github.com/seperman/redisworks


2
ちなみにhmset、変数をdictに設定すると、RedisWorksは内部で使用しroot.something = {}ます。したがって、設定すると、hmset空の辞書が許可されないため、DataErrorが発生します。redisのドキュメントにはこれが記載されていないため、これについて言及します。
hlongmore

面白い。はい、使用しますhmset。これを調べます。@hlongmore
Seperman

しかし、それでも、辞書のバイトをサポートできますか?
ZettaCircl

13

基本的な答えはすでに他の人から出されているので、それにいくつか追加したいと思います。

以下は、型の値REDISを使用して基本的な操作を実行するためのコマンドHashMap/Dictionary/Mappingです。

  1. HGET =>渡された単一のキーの値を返します
  2. HSET =>単一キーの値を設定/更新します
  3. HMGET =>渡された単一/複数のキーの値を返します
  4. HMSET =>複数のキーの値を設定/更新します
  5. HGETALL =>マッピング内のすべての(キー、値)ペアを返します。

以下は、redis-pyライブラリ内のそれぞれのメソッドです:-

  1. HGET => hget
  2. HSET => hset
  3. HMGET => hmget
  4. HMSET => hmset
  5. HGETALL => hgetall

上記のセッターメソッドはすべて、マッピングが存在しない場合はマッピングを作成します。マッピングのマッピング/キーが存在しない場合、上記のすべてのゲッターメソッドでエラー/例外が発生することはありません。

Example:
=======
In [98]: import redis
In [99]: conn = redis.Redis('localhost')

In [100]: user = {"Name":"Pradeep", "Company":"SCTL", "Address":"Mumbai", "Location":"RCP"}

In [101]: con.hmset("pythonDict", {"Location": "Ahmedabad"})
Out[101]: True

In [102]: con.hgetall("pythonDict")
Out[102]:
{b'Address': b'Mumbai',
 b'Company': b'SCTL',
 b'Last Name': b'Rajpurohit',
 b'Location': b'Ahmedabad',
 b'Name': b'Mangu Singh'}

In [103]: con.hmset("pythonDict", {"Location": "Ahmedabad", "Company": ["A/C Pri
     ...: sm", "ECW", "Musikaar"]})
Out[103]: True

In [104]: con.hgetall("pythonDict")
Out[104]:
{b'Address': b'Mumbai',
 b'Company': b"['A/C Prism', 'ECW', 'Musikaar']",
 b'Last Name': b'Rajpurohit',
 b'Location': b'Ahmedabad',
 b'Name': b'Mangu Singh'}

In [105]: con.hget("pythonDict", "Name")
Out[105]: b'Mangu Singh'

In [106]: con.hmget("pythonDict", "Name", "Location")
Out[106]: [b'Mangu Singh', b'Ahmedabad']

私はそれが物事をより明確にすることを願っています。


キーを動的にする方法
ak3191 2018年

12

Python dictをredisに保存する場合は、json文字列として保存することをお勧めします。

import redis

r = redis.StrictRedis(host='localhost', port=6379, db=0)
mydict = { 'var1' : 5, 'var2' : 9, 'var3': [1, 5, 9] }
rval = json.dumps(mydict)
r.set('key1', rval)

取得中にjson.loadsを使用して逆シリアル化します

data = r.get('key1')
result = json.loads(data)
arr = result['var3']

json関数によってシリアル化されていないタイプ(バイトなど)はどうですか?

json関数でシリアル化できないタイプのエンコーダー/デコーダー関数を記述できます。例えば。バイト配列用のbase64 / ASCIIエンコーダ/デコーダ関数の記述。


たとえば、バイト値のdictなど、一部のdictをJSONにシリアル化できないため、これに反対しました。
トミー

1
デフォルトでエンコード/デコードできないタイプのエンコーダー/デコーダー関数(要件に応じて、たとえばbase64 / asciiエンコード)を作成できます。
Saji Xavier

@ Tommy-hmset / hgetallを使用している場合でも、redisでサポートされていないタイプをエンコード/デコードする必要がある場合があります。
Saji Xavier

1
「...後者の操作はO(N)」について意見が分かれています。Nは、キーにリンクしているフィールドの数です。N SET / GETまたは1HGET / HSETを実行することは、同じ複雑さです。参照:redis.io/commands/hmset時間的には、HGET / HSETはアトミックトランザクションであるため、REDISによってより高速に実行されます。複雑さをRedisからPythonコードに移行しているだけです。
ZettaCircl

hmsetの利点は、dictの特定のサブパートのみを取得できることです。jsonではそれを失うので、これはピクルスや他のものと同じくらい良いです。
ホルヘ・レイタオ

5

redisによって承認されているMessagePackの使用を検討するかもしれません。

import msgpack

data = {
    'one': 'one',
    'two': 2,
    'three': [1, 2, 3]
}

await redis.set('my-key', msgpack.packb(data))
val = await redis.get('my-key')
print(msgpack.unpackb(val))

# {'one': 'one', 'two': 2, 'three': [1, 2, 3]}

使用msgpack-のpythonaioredisを


4

あなたが問題に取り組むことができる他の方法:

import redis
conn = redis.Redis('localhost')

v={'class':'user','grants': 0, 'nome': 'Roberto', 'cognome': 'Brunialti'}

y=str(v)
print(y['nome']) #<=== this return an error as y is actually a string
conn.set('test',y)

z=eval(conn.get('test'))
print(z['nome']) #<=== this really works!

効率/速度についてはテストしていません。


3

redis SETコマンドは、任意のデータではなく文字列を格納します。redis HSETコマンドを使用して、次のようなredisハッシュとしてdictを保存してみてください。

for k,v in my_dict.iteritems():
    r.hset('my_dict', k, v)

しかし、redisデータ型とpythonデータ型は完全には一致していません。Python dictは任意にネストできますが、redisハッシュでは値が文字列である必要があります。あなたが取ることができる別のアプローチは、Pythonデータを文字列に変換し、それをredisに保存することです。

r.set('this_dict', str(my_dict))

次に、文字列を取得したら、それを解析してPythonオブジェクトを再作成する必要があります。


1
彼は自分のデータをjsonに変換し、結果をredisに保存できます
Narcisse Doudieu Siewe 2016年

3

HMSETは非推奨です。これで、次のように辞書でHSETを使用できます。

import redis
r = redis.Redis('localhost')

key = "hashexample" 
queue_entry = { 
    "version":"1.2.3", 
    "tag":"main", 
    "status":"CREATED",  
    "timeout":"30"
    }
r.hset(key,None,None,queue_entry)

ありがとう!私はこれがすべて綴られているドキュメントを見つけようとしています。どこか分かりますか。たとえば、2つの「なし」は何ですか。
NealWalters

@NealWalters:非推奨の警告については、HMSETコマンドページの行を参照してください-redis.io/commands/hmset
SaranshSingh20年

0

2017年以来比較的新しいrejson-pyを試してみてください。この紹介を見てください。

from rejson import Client, Path

rj = Client(host='localhost', port=6379)

# Set the key `obj` to some object
obj = {
    'answer': 42,
    'arr': [None, True, 3.14],
    'truth': {
        'coord': 'out there'
    }
}
rj.jsonset('obj', Path.rootPath(), obj)

# Get something
print 'Is there anybody... {}?'.format(
    rj.jsonget('obj', Path('.truth.coord'))
)

# Delete something (or perhaps nothing), append something and pop it
rj.jsondel('obj', Path('.arr[0]'))
rj.jsonarrappend('obj', Path('.arr'), 'something')
print '{} popped!'.format(rj.jsonarrpop('obj', Path('.arr')))

# Update something else
rj.jsonset('obj', Path('.answer'), 2.17)

0

Redisでデータを整理する方法が正確にわからない場合は、結果の解析など、いくつかのパフォーマンステストを行いました。私が使用した辞書(d)には437.084キー(md5形式)があり、この形式の値は次のとおりです。

{"path": "G:\tests\2687.3575.json",
 "info": {"f": "foo", "b": "bar"},
 "score": 2.5}

最初のテスト(redisキー値マッピングへのデータの挿入):

conn.hmset('my_dict', d)  # 437.084 keys added in 8.98s

conn.info()['used_memory_human']  # 166.94 Mb

for key in d:
    json.loads(conn.hget('my_dict', key).decode('utf-8').replace("'", '"'))
    #  41.1 s

import ast
for key in d:
    ast.literal_eval(conn.hget('my_dict', key).decode('utf-8'))
    #  1min 3s

conn.delete('my_dict')  # 526 ms

2番目のテスト(Redisキーに直接データを挿入):

for key in d:
    conn.hmset(key, d[key])  # 437.084 keys added in 1min 20s

conn.info()['used_memory_human']  # 326.22 Mb

for key in d:
    json.loads(conn.hgetall(key)[b'info'].decode('utf-8').replace("'", '"'))
    #  1min 11s

for key in d:
    conn.delete(key)
    #  37.3s

ご覧のとおり、2番目のテストでは、hgetall(key)がすでにdictを返しますが、ネストされたものは返さないため、「info」値のみを解析する必要があります。

そしてもちろん、PythonのdictとしてRedisを使用する最良の例は、最初のテストです

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.