如何使用Redis存储和检索字典


93
# 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

Answers:


160

您可以这样做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'}

48
如果它是嵌套的数据结构,而不是简单的字典,例如包含一些数组等。serialzie将数据json.dumps()写为字符串,并从redis用户检索json.loads()以反序列化回python数据结构后
andilabs

7
json.dumps()并且json.loads()只有在您的字典键始终为字符串的情况下才可以使用。如果不是,那么您可以考虑使用泡菜。
ryechus

6
json与字节不兼容,因此json序列化不是全局解决方案,例如,如果您的字典具有字节值,则此方法将不起作用。
汤米

8
值得注意的是,的文档hmset没有告诉您这一点,但是如果您尝试存储空字典,则会引发DataError。
hlongmore

1
@Pradeep我们如何使密钥动态化。假设每15分钟插入一次数据,那么我如何使密钥动态化
ak3191 '18

36

您可以腌制您的字典并另存为字符串。

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)

11
的确如此,但是根据读写的速度,这可能会增加严重的开销。酸洗速度很慢
汤米

1
请注意,如果与用户输入一起使用,则您的服务器易于执行远程代码pickle.loads仅应用于100%受信任的数据
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 = {},则会出现DataError,因为hmset不允许空字典。我之所以这样说是因为redis的文档没有告诉您这一点。
hlongmore

有趣。是的,它确实可以使用hmset。我将对此进行调查。@hlongmore
Seperman '18

但是,它仍然可以支持字典中的字节吗?
ZettaCircl

12

正如其他人已经给出的基本答案一样,我想补充一下。

以下是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

如果不存在映射,则上述所有setter方法都会创建该映射。如果映射中的映射/键不存在,则上述所有getter方法都不会引发错误/异常。

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 '18

11

如果要在redis中存储python字典,最好将其存储为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编码器/解码器功能。


我对此表示反对,因为某些字典无法序列化为JSON,例如,带有字节值的字典。
汤米

1
您可以为默认情况下无法进行编码/解码的类型编写编码器/解码器功能(根据要求,例如base64 / ascii编码)。
Saji Xavier

@Tommy-即使使用hmset / hgetall,也可能需要对redis不支持的类型进行编码/解码。
Saji Xavier

1
关于“ ...后面的运算是O(N)”,存在分歧。N是链接到键的字段数。进行N SET / GET或1 HGET / HSET的复杂度相同。请参阅:redis.io/commands/hmset在时间上,HGET / HSET是原子事务,因此REDIS可以更快地执行。您只是将复杂性从Redis转移到了Python代码。
ZettaCircl

hmset的优点是可以仅检索dict的某些子部分。使用json我们会丢失它,所以这和泡菜或其他东西一样好。
豪尔赫·雷涛


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哈希,例如

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

但是redis数据类型和python数据类型不太一致。Python字典可以任意嵌套,但是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)

谢谢!我正在尝试找到所有说明的文档。你知道在哪里吗。例如,两个“ Nones”有什么用。
NealWalters

@NealWalters:请参阅HMSET命令页面上的行-redis.io/commands/hmset以获取弃用警告。
萨兰什·辛格

0

尝试rejson-py,这是自2017年以来相对较新的内容。请参阅介绍

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

第二次测试(将数据直接插入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

如您所见,在第二个测试中,仅需解析“ info”值,因为hgetall(key)已返回dict,但未返回嵌套的dict。

当然,将Redis用作python dict的最佳示例是First Test

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.