Redis ile bir sözlük nasıl saklanır ve alınır


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

My_dict'i nasıl saklar ve redis ile geri alırım. Örneğin, aşağıdaki kod çalışmıyor.

#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

Yanıtlar:


160

Bunu şu şekilde yapabilirsiniz hmset(birden fazla anahtar kullanılarak ayarlanabilir 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
basitçe dikteden ziyade iç içe geçmiş bir veri yapısı ise, örneğin bazı diziler vb. içeriyorsa, verilerinizi json.dumps()dizgi olarak yazarak json.loads()seri hale getirin ve redis kullanıcısından sonra yeniden python veri yapısına geri döndürmek için geri alın
andilabs

7
json.dumps()ve json.loads()sadece sözlük anahtarlarınızın her zaman dizge olması durumunda sorun yaşamazsanız işe yarar. Değilseniz, turşu kullanmayı düşünebilirsiniz.
ryechus

6
json baytlarla uyumlu değildir, bu nedenle json serilizasyonu global bir çözüm değildir, örneğin, bayt değerine sahip bir dict'iniz varsa bu çalışmayacaktır.
Tommy

8
Unutmayın, dokümantasyonu hmsetsize bunu söylemez, ancak boş bir dikteyi saklamaya çalışırsanız bir DataError oluşturur.
hlongmore

1
@Pradeep anahtarı nasıl dinamik hale getirebiliriz. verinin her 15 dakikada bir eklendiğini varsayalım, böylece anahtarın dinamikliğini nasıl sağlayabilirim
ak3191

36

diktenizi toplayabilir ve dizgi olarak kaydedebilirsiniz.

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
Bu doğrudur, ancak okuma ve yazma oranına bağlı olarak, bu ciddi bir ek yük getirebilir. Turşu yavaş bir işlemdir
Tommy

1
Bu kullanıcı girişi ile kullanılırsa sunucu unutmayınız uzaktan kod exection eğilimli , pickle.loadssadece% 100 güvenilir veriler üzerinde kullanılması gerektiğini edilir
Paradoxis

16

Başka bir yol: RedisWorkskitaplığı kullanabilirsiniz .

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 türlerini Redis türlerine dönüştürür ve bunun tersi de geçerlidir.

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

Feragatname: Kütüphaneyi yazdım. İşte kod: https://github.com/seperman/redisworks


2
Unutmayın, RedisWorks bir dikteye hmsetbir değişken ayarlarsanız kaputun altında kullanır ve böylece yaparsanız root.something = {}bir DataError alırsınız çünkü hmsetboş sözlüklere izin vermez. Bunu söylüyorum çünkü redis belgeleri size bunu söylemiyor.
hlongmore

İlginç. Evet kullanıyor hmset. Bunu araştıracağım. @hlongmore
Seperman

Ama yine de sözlükteki baytları destekleyebilir mi?
ZettaCircl

12

Temel cevabın zaten başkaları tarafından verilmiş olduğu gibi, ona bazılarını eklemek istiyorum.

Tip değerleri REDISile temel işlemleri gerçekleştirmek için komutlar HashMap/Dictionary/Mappingaşağıdadır.

  1. HGET => Geçilen tek anahtar için değeri döndürür
  2. HSET => tek anahtar için değeri ayarla / güncelle
  3. HMGET => Geçilen tek / çoklu anahtarlar için değeri döndürür
  4. HMSET => çoklu anahtar için değerleri ayarlayın / güncelleyin
  5. HGETALL => Eşlemedeki tüm (anahtar, değer) çiftlerini döndürür.

Aşağıdakiler redis-pykütüphanedeki ilgili yöntemlerdir : -

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

Yukarıdaki ayarlayıcı yöntemlerinin tümü, mevcut değilse eşlemeyi oluşturur. Haritalamada eşleme / anahtar yoksa, yukarıdaki alıcı yöntemlerinin tümü hata / istisnalara neden olmaz.

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

Umarım işleri daha netleştirir.


temel dinamik nasıl yapılır
ak3191

12

Bir python diktesini redis'te saklamak istiyorsanız, onu json dizesi olarak saklamak daha iyidir.

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 kullanarak serileştirmeyi geri alırken

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

Peki json işlevleri tarafından serileştirilmemiş türler (ör. Baytlar)?

Json işlevleri tarafından serileştirilemeyen türler için kodlayıcı / kod çözücü işlevleri yazabilirsiniz. Örneğin. bayt dizisi için base64 / ascii kodlayıcı / kod çözücü işlevi yazılıyor.


Bunu, bazı diktlerin JSON'a serileştirilememesi nedeniyle, örneğin bayt değerine sahip diktler için olumsuz oy verdim.
Tommy

1
Varsayılan olarak kodlanamayan / kodu çözülemeyen türler için bir kodlayıcı / kod çözücü işlevi (gereksinime göre, örn. Base64 / ascii kodlaması) yazabilirsiniz.
Saji Xavier

@Tommy - hmset / hgetall kullansanız bile, redis tarafından desteklenmeyen türleri kodlamanız / kod çözmeniz gerekebilir.
Saji Xavier

1
"... son işlem O (N)" konusunda hemfikir değil. N, anahtara bağlantınız olan alanların sayısıdır. N SET / GET veya 1 HGET / HSET yapmak aynı karmaşıklıktır. Bkz: redis.io/commands/hmset Zaman akıllı, HGET / HSET atomik işlem, ve bu yüzden daha hızlı REDIS tarafından yapılmaktadır. Siz sadece karmaşıklığı Redis'ten Python Koduna taşıyorsunuz.
ZettaCircl

Hmset'in avantajı, diktenin yalnızca belirli alt parçalarını alma olasılığıdır. JSON ile bunu kaybediyoruz, bu yüzden bu turşu veya başka bir şey kadar iyidir.
Jorge Leitao

5

Redis tarafından onaylanan MessagePack'i kullanmayı düşünebilirsiniz .

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

Kullanılması msgpack-python ve aioredis


4

Konuya yaklaşmanın başka bir yolu:

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!

Verimlilik / hız açısından test etmedim.


3

Redis SET komutu, rastgele verileri değil, bir dizeyi saklar. Dikteyi redis hash olarak saklamak için redis HSET komutunu kullanmayı deneyebilirsiniz.

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

ancak redis veri türleri ve python veri türleri tam olarak sıralanmıyor. Python dicts isteğe bağlı olarak yuvalanabilir, ancak bir redis hash değeri, değerinizin bir dizge olmasını gerektirecektir. Alabileceğiniz başka bir yaklaşım da python verilerinizi dizeye dönüştürmek ve bunu redis biçiminde saklamaktır.

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

ve sonra dizeyi çıkardığınızda, python nesnesini yeniden oluşturmak için onu ayrıştırmanız gerekecektir.


1
verilerini json'a dönüştürebilir ve sonucu redis'de saklayabilir
Narcisse Doudieu Siewe

3

HMSET kullanımdan kaldırıldı. Artık HSET'i aşağıdaki gibi bir sözlükle kullanabilirsiniz:

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)

Teşekkürler! Tüm bunların yazıldığı dokümanı bulmaya çalışıyorum. Onun nerede olduğunu biliyor musun. Örneğin, iki "Hayır" ne için?
NealWalters

@NealWalters: Kullanımdan kaldırma uyarısı için HMSET komut sayfasındaki - redis.io/commands/hmset satırına bakın.
Saransh Singh

0

Deneyin rejson-py şuna 2017 Look beri nispeten yeni giriş .

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'te verileri nasıl organize edeceğinizi tam olarak bilmiyorsanız, sonuçların ayrıştırılması da dahil olmak üzere bazı performans testleri yaptım. Kullandığım sözlüğün ( d ) 437.084 anahtarı (md5 formatı) vardı ve bu formun değerleri:

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

İlk Test (redis anahtar / değer eşlemesine veri ekleme):

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

İkinci Test (verileri doğrudan Redis anahtarlarına ekleme):

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

Gördüğünüz gibi, ikinci testte, yalnızca 'bilgi' değerlerinin ayrıştırılması gerekir, çünkü hgetall (anahtar) zaten bir dikte döndürür, ancak iç içe bir dict döndürmez.

Ve elbette, Redis'i python'un diktatörleri olarak kullanmanın en iyi örneği, İlk Test

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.