Cara menyimpan dan mengambil kamus dengan redis

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

Bagaimana cara menyimpan my_dict dan mengambilnya dengan redis. Misalnya, kode berikut tidak berfungsi.

#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
PiccolMan
sumber

Jawaban:

160

Anda dapat melakukannya dengan hmset(beberapa kunci dapat diatur menggunakan 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'}
PradeepK
sumber
48
jika itu adalah struktur data bersarang daripada hanya mendikt, misalnya berisi beberapa larik, dll. Serialzie data Anda dengan json.dumps()menulis sebagai string dan setelah mengambil dari pengguna redis json.loads()untuk deserialisasi kembali ke struktur data python
andilabs
7
json.dumps()dan json.loads()hanya akan berfungsi jika Anda baik-baik saja dengan kunci kamus Anda yang selalu berupa string. Jika tidak, Anda mungkin mempertimbangkan untuk menggunakan acar.
ryechus
6
json tidak kompatibel dengan byte sehingga serilisasi json bukanlah solusi global, misalnya, jika Anda memiliki dict dengan nilai byte, ini tidak akan berfungsi.
Tommy
8
Sebagai catatan, dokumentasi untuk hmsettidak memberi tahu Anda ini, tetapi memunculkan DataError jika Anda mencoba untuk menyimpan dikt yang kosong.
hlongmore
1
@Pradeep bagaimana kita dapat membuat kunci menjadi dinamis. misalkan data disisipkan setiap 15 menit jadi bagaimana saya dapat membuat kunci dinamis
ak3191
36

Anda dapat membuat acar dict Anda dan menyimpannya sebagai string.

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)
DaveQ
sumber
12
Ini benar, tetapi tergantung pada tingkat pembacaan dan penulisan, ini dapat menambah overhead yang serius. Pengawetan adalah operasi yang lambat
Tommy
1
Harap dicatat bahwa jika ini digunakan dengan input pengguna, server Anda rentan terhadap pemeriksaan kode jarak jauh , pickle.loadsseharusnya hanya digunakan pada 100% data tepercaya
Paradoxis
16

Cara lain: Anda bisa menggunakan RedisWorksperpustakaan.

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

Ini mengubah jenis python menjadi jenis Redis dan sebaliknya.

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

Penafian: Saya menulis perpustakaan. Ini kodenya: https://github.com/seperman/redisworks

Seperman
sumber
2
Sebagai catatan, RedisWorks menggunakan di hmsetbawah tenda jika Anda menyetel variabel ke dikt, dan dengan demikian jika Anda melakukannya, root.something = {}Anda akan mendapatkan DataError, karena hmsettidak mengizinkan kamus kosong. Saya menyebutkan ini karena dokumentasi untuk redis tidak memberi tahu Anda hal ini.
hlongmore
Menarik. Ya, itu berguna hmset. Saya akan memeriksa ini. @hlongmore
Seperman
Tapi tetap, bisakah itu mendukung byte dalam kamus?
ZettaCircl
12

Karena jawaban dasar telah diberikan oleh orang lain, saya ingin menambahkan beberapa.

Berikut adalah perintah REDISuntuk melakukan operasi dasar dengan HashMap/Dictionary/Mappingnilai tipe.

  1. HGET => Mengembalikan nilai untuk kunci tunggal yang dilewatkan
  2. HSET => set / update nilai untuk kunci tunggal
  3. HMGET => Mengembalikan nilai untuk satu / beberapa kunci yang diteruskan
  4. HMSET => set / perbarui nilai untuk beberapa kunci
  5. HGETALL => Mengembalikan semua pasangan (kunci, nilai) dalam pemetaan.

Berikut adalah metode masing-masing di redis-pyperpustakaan: -

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

Semua metode penyetel di atas membuat pemetaan, jika tidak ada. Semua metode pengambil di atas tidak memunculkan kesalahan / pengecualian, jika pemetaan / kunci dalam pemetaan tidak ada.

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

Saya harap, ini membuat semuanya lebih jelas.

Mangu Singh Rajpurohit
sumber
bagaimana Anda dapat membuat kunci menjadi dinamis
ak3191
12

Jika Anda ingin menyimpan dikt python di redis, lebih baik menyimpannya sebagai string 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)

Saat mengambil de-serialisasi menggunakan json.loads

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

Bagaimana dengan tipe (mis. Byte) yang tidak diserialkan oleh fungsi json?

Anda dapat menulis fungsi encoder / decoder untuk jenis yang tidak dapat diserialkan oleh fungsi json. misalnya. menulis fungsi encoder / decoder base64 / ascii untuk array byte.

Saji Xavier
sumber
Saya menurunkan suara ini karena beberapa dicts tidak dapat diserialkan ke JSON, misalnya, dicts dengan nilai byte.
Tommy
1
Anda dapat menulis fungsi encoder / decoder (sesuai dengan kebutuhan, misalnya encoding base64 / ascii) untuk jenis yang tidak dapat dienkode / didekode secara default.
Saji Xavier
@Tommy - meskipun menggunakan hmset / hgetall, Anda mungkin perlu mengenkode / mendekode jenis yang tidak didukung oleh redis.
Saji Xavier
1
Tidak setuju tentang "... operasi terakhir adalah O (N)." N adalah jumlah bidang yang Anda tautkan ke kunci. Melakukan N SET / GET atau 1 HGET / HSET adalah kompleksitas yang sama. Lihat: redis.io/commands/hmset Dari segi waktu, HGET / HSET adalah transaksi atomik, sehingga dilakukan lebih cepat oleh REDIS. Anda baru saja memindahkan kompleksitas dari Redis ke Python Code.
ZettaCircl
Keuntungan dari hmset adalah kemungkinan untuk mengambil hanya sub-bagian tertentu dari dict. Dengan json kami kehilangan itu, jadi ini sebagus acar atau hal lainnya.
Jorge Leitao
5

Seseorang mungkin mempertimbangkan untuk menggunakan MessagePack yang didukung oleh redis.

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

Menggunakan msgpack-python dan aioredis

Ohad Lahav
sumber
4

Cara lain untuk mendekati masalah ini:

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!

Saya tidak mengujinya untuk efisiensi / kecepatan.

roberto
sumber
3

Perintah redis SET menyimpan string, bukan data arbitrer. Anda dapat mencoba menggunakan perintah redis HSET untuk menyimpan dict sebagai hash redis dengan sesuatu seperti

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

tetapi tipe data redis dan tipe data python tidak cukup berbaris. Dicts Python dapat disarangkan secara sewenang-wenang, tetapi hash redis akan mengharuskan nilai Anda adalah string. Pendekatan lain yang dapat Anda ambil adalah mengonversi data python Anda menjadi string dan menyimpannya di redis, seperti

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

dan kemudian saat Anda mengeluarkan string, Anda perlu menguraikannya untuk membuat ulang objek python.

Jesusaur
sumber
1
dia dapat mengubah datanya menjadi json dan menyimpan hasilnya di redis
Narcisse Doudieu Siewe
3

HMSET tidak digunakan lagi. Anda sekarang dapat menggunakan HSET dengan kamus sebagai berikut:

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)
Tad Guski
sumber
Terima kasih! Saya mencoba mencari dokumen di mana semua ini dijabarkan. Apa kamu tahu di mana itu. Misalnya, untuk apa dua "Nones".
NealWalters
@NealWalters: Lihat baris pada halaman perintah HMSET - redis.io/commands/hmset untuk peringatan penghentian.
Saransh Singh
0

Coba rejson-py yang relatif baru sejak 2017. Lihat pengantar ini .

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)
Kevin Zhu
sumber
0

Jika Anda tidak tahu persis bagaimana mengatur data di Redis, saya melakukan beberapa tes kinerja, termasuk hasil parsing. Dictonary yang saya gunakan ( d ) memiliki 437.084 kunci (format md5), dan nilai dari formulir ini:

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

Tes Pertama (memasukkan data ke dalam pemetaan nilai kunci 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

Tes Kedua (memasukkan data langsung ke kunci 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

Seperti yang Anda lihat, pada pengujian kedua, hanya nilai 'info' yang harus diurai, karena hgetall (key) sudah mengembalikan dict, tetapi bukan yang bertingkat.

Dan tentu saja, contoh terbaik menggunakan Redis sebagai penis python, adalah Tes Pertama

Tavy
sumber