Cách lưu trữ và truy xuất từ ​​điển với redis


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

Làm cách nào để lưu trữ my_dict và lấy nó bằng redis. Ví dụ, mã sau đây không hoạt động.

#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

Câu trả lời:


160

Bạn có thể làm điều đó bằng cách hmset(có thể đặt nhiều phím bằng cách sử dụng 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
nếu nó là cấu trúc dữ liệu lồng nhau chứ không phải chỉ đơn giản là dict, ví dụ như có chứa một số mảng, vv serialzie dữ liệu của bạn với json.dumps()ghi như chuỗi và sau khi truy xuất từ redis dùng json.loads()cho deserializing nó trở lại cấu trúc dữ liệu python
andilabs

7
json.dumps()json.loads()sẽ chỉ hoạt động nếu bạn ổn với các khóa từ điển của mình luôn là chuỗi. Nếu không, bạn có thể cân nhắc sử dụng dưa chua.
ryechus

6
json không tương thích với byte nên việc serization json không phải là giải pháp toàn cục, ví dụ: nếu bạn có một dict với giá trị byte, điều này sẽ không hoạt động.
Tommy

8
Xin lưu ý, tài liệu cho hmsetkhông cho bạn biết điều này, nhưng nó gây ra lỗi DataError nếu bạn cố gắng lưu trữ một mệnh đề trống.
hlongmore

1
@Pradeep cách chúng tôi có thể làm cho khóa động. giả sử dữ liệu được việc chèn từng phút 15 vậy làm thế nào tôi có thể làm cho động chủ chốt
ak3191

36

bạn có thể chọn mệnh lệnh của mình và lưu dưới dạng chuỗi.

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
Điều này đúng, nhưng tùy thuộc vào tốc độ đọc và ghi, điều này có thể làm tăng chi phí nghiêm trọng. Pickling là một hoạt động chậm chạp
Tommy

1
Xin lưu ý rằng nếu điều này được sử dụng với đầu vào của người dùng, máy chủ của bạn dễ bị loại bỏ mã từ xa , pickle.loadschỉ nên được sử dụng trên dữ liệu đáng tin cậy 100%
Paradoxis

16

Một cách khác: bạn có thể sử dụng RedisWorksthư viện.

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

Nó chuyển đổi loại python thành loại Redis và ngược lại.

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

Tuyên bố từ chối trách nhiệm: Tôi đã viết thư viện. Đây là mã: https://github.com/seperman/redisworks


2
Lưu ý, RedisWorks sử dụng ẩn hmsetnếu bạn đặt một biến thành chính tả, và do đó nếu bạn làm vậy, root.something = {}bạn sẽ nhận được Lỗi dữ liệu, vì hmsetkhông cho phép các từ điển trống. Tôi đề cập đến điều này vì tài liệu cho redis không cho bạn biết điều này.
hlongmore

Hấp dẫn. Có nó sử dụng hmset. Tôi sẽ xem xét này. @hlongmore
Chín

Nhưng vẫn còn, nó có thể hỗ trợ byte trong từ điển không?
ZettaCircl

12

Vì câu trả lời cơ bản đã được đưa ra bởi những người khác, tôi muốn thêm một số vào nó.

Sau đây là các lệnh REDISđể thực hiện các thao tác cơ bản với HashMap/Dictionary/Mappingcác giá trị kiểu.

  1. HGET => Trả về giá trị cho một khóa được truyền vào
  2. HSET => đặt / cập nhật giá trị cho khóa đơn
  3. HMGET => Trả về giá trị cho một / nhiều khóa được truyền
  4. HMSET => đặt / cập nhật các giá trị cho nhiều khóa
  5. HGETALL => Trả về tất cả các cặp (khóa, giá trị) trong ánh xạ.

Sau đây là các phương thức tương ứng của chúng trong redis-pythư viện: -

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

Tất cả các phương thức setter ở trên tạo ánh xạ, nếu nó không tồn tại. Tất cả các phương thức getter ở trên không gây ra lỗi / ngoại lệ, nếu ánh xạ / khóa trong ánh xạ không tồn tại.

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

Tôi hy vọng, nó làm cho mọi thứ rõ ràng hơn.


làm thế nào bạn có thể làm cho động chủ chốt
ak3191

11

Nếu bạn muốn lưu trữ một python dict trong redis, tốt hơn nên lưu trữ nó dưới dạng chuỗi 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)

Trong khi truy xuất de-serialize nó bằng json.loads

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

Còn các loại (ví dụ: byte) không được tuần tự hóa bởi các hàm json thì sao?

Bạn có thể viết các hàm mã hóa / giải mã cho các loại mà hàm json không thể tuần tự hóa. ví dụ. viết hàm mã hóa / giải mã base64 / ascii cho mảng byte.


Tôi đã phản đối điều này vì một số phân số không thể được tuần tự hóa thành JSON, ví dụ: phân số có giá trị byte.
Tommy

1
Bạn có thể viết hàm mã hóa / giải mã (theo yêu cầu, ví dụ: mã hóa base64 / ascii) cho các loại không thể mã hóa / giải mã theo mặc định.
Saji Xavier

@Tommy - ngay cả khi sử dụng hmset / hgetall, bạn có thể cần mã hóa / giải mã các loại không được redis hỗ trợ.
Saji Xavier

1
Không đồng ý về "... hoạt động sau là O (N)." N là số trường bạn có liên kết đến khóa. Thực hiện N SET / GET hoặc 1 HGET / HSET có cùng độ phức tạp. Xem: redis.io/commands/hmset Theo thời gian, HGET / HSET là giao dịch nguyên tử và do đó REDIS thực hiện nhanh hơn. Bạn chỉ đang chuyển sự phức tạp từ Redis sang Python Code.
ZettaCircl

Ưu điểm của hmset là khả năng truy xuất chỉ một số phần phụ của dict. Với json, chúng ta mất điều đó, vì vậy điều này cũng tốt như dưa muối hay thứ khác.
Jorge Leitao

5

Người ta có thể cân nhắc sử dụng MessagePack được redis xác nhận.

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]}

Sử dụng msgpack-pythonaioredis


4

Một cách khác bạn có thể tiếp cận vấn đề:

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!

Tôi đã không kiểm tra nó về hiệu quả / tốc độ.


3

Lệnh redis SET lưu trữ một chuỗi, không phải dữ liệu tùy ý. Bạn có thể thử sử dụng lệnh redis HSET để lưu trữ dict dưới dạng hàm băm redis với một cái gì đó như

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

nhưng kiểu dữ liệu redis và kiểu dữ liệu python không hoàn toàn giống nhau. Các dãy số trong Python có thể được lồng vào nhau một cách tùy ý, nhưng một hàm băm redis sẽ yêu cầu giá trị của bạn là một chuỗi. Một cách tiếp cận khác mà bạn có thể thực hiện là chuyển đổi dữ liệu python của bạn thành chuỗi và lưu trữ dữ liệu đó trong redis, giống như

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

và sau đó khi bạn lấy chuỗi ra, bạn sẽ cần phải phân tích cú pháp nó để tạo lại đối tượng python.


1
anh ấy có thể chuyển đổi dữ liệu của mình sang json và lưu trữ kết quả trong redis
Narcisse Doudieu Siewe

3

HMSET không được dùng nữa. Bây giờ bạn có thể sử dụng HSET với từ điển như sau:

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)

Cảm ơn! Tôi đang cố gắng tìm tài liệu nơi tất cả những điều này được viết ra. Bạn có biết nó ở đâu không. Ví dụ, hai "Nones" để làm gì.
NealWalters

@NealWalters: Xem dòng trên trang lệnh HMSET - redis.io/commands/hmset để biết cảnh báo không dùng nữa.
Saransh Singh

0

Hãy thử rejson-py tương đối mới từ năm 2017. Hãy xem phần giới thiệu này .

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

Nếu bạn không biết chính xác cách tổ chức dữ liệu trong Redis, tôi đã thực hiện một số bài kiểm tra hiệu suất, bao gồm cả phân tích cú pháp kết quả. Văn bản chính tả tôi đã sử dụng ( d ) có 437.084 khóa (định dạng md5) và các giá trị của biểu mẫu này:

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

Thử nghiệm đầu tiên (chèn dữ liệu vào ánh xạ khóa-giá trị 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

Thử nghiệm thứ hai (chèn dữ liệu trực tiếp vào các khóa 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

Như bạn có thể thấy, trong thử nghiệm thứ hai, chỉ các giá trị 'thông tin' mới phải được phân tích cú pháp, bởi vì hgetall (khóa) đã trả về một chính tả, nhưng không phải là một giá trị lồng nhau.

Và tất nhiên, ví dụ điển hình nhất về việc sử dụng Redis làm các đặc điểm của python, là Thử nghiệm đầu tiên

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.