So speichern und rufen Sie ein Wörterbuch mit redis ab

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

Wie würde ich my_dict speichern und mit redis abrufen? Der folgende Code funktioniert beispielsweise nicht.

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

Antworten:

151

Sie können dies tun, indem hmset(mehrere Schlüssel können mit eingestellt werden 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
quelle
44
Wenn es sich um eine verschachtelte Datenstruktur handelt, anstatt nur zu diktieren, z. B. um einige Arrays usw. zu enthalten, serialisieren Sie Ihre Daten mit json.dumps()Schreiben als Zeichenfolge und nachdem Sie vom Redis-Benutzer abgerufen wurden, json.loads()um sie wieder in die Python-Datenstruktur zu deserialisieren
andilabs
7
json.dumps()und json.loads()funktioniert nur, wenn Ihre Wörterbuchschlüssel immer Zeichenfolgen sind. Wenn Sie nicht sind, können Sie Gurke verwenden.
Ryechus
6
json ist nicht mit Bytes kompatibel, daher ist die json-Serilisierung keine globale Lösung. Wenn Sie beispielsweise ein Diktat mit einem Bytewert haben, funktioniert dies nicht.
Tommy
6
In der Dokumentation zu wird hmsetdies nicht angegeben, es wird jedoch ein DataError ausgelöst, wenn Sie versuchen, ein leeres Diktat zu speichern.
Hlongmore
1
@Pradeep, wie wir den Schlüssel dynamisch machen können. Angenommen, die Daten werden alle 15 Minuten eingefügt, damit ich den Schlüssel dynamisch gestalten kann
ak3191
33

Sie können Ihr Diktat auswählen und als Zeichenfolge speichern.

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
quelle
8
Dies ist wahr, aber abhängig von der Rate der Lese- und Schreibvorgänge kann dies zu einem erheblichen Overhead führen. Beizen ist eine langsame Operation
Tommy
1
Bitte beachten Sie, dass , wenn diese mit Benutzereingabe verwendet, um Ihren Server zu Remotecode exection anfällig ist , pickle.loadswird nur verwendet werden soll , auf 100% Daten vertraut
paradoxis
16

Ein anderer Weg: Sie können die RedisWorksBibliothek verwenden.

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

Es konvertiert Python-Typen in Redis-Typen und umgekehrt.

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

Haftungsausschluss: Ich habe die Bibliothek geschrieben. Hier ist der Code: https://github.com/seperman/redisworks

Seperman
quelle
1
Zu beachten ist, dass RedisWorks hmsetunter der Haube verwendet, wenn Sie eine Variable auf ein Diktat setzen. Wenn Sie dies tun, erhalten root.something = {}Sie einen DataError, da hmsetkeine leeren Wörterbücher zulässig sind . Ich erwähne dies, weil die Dokumentation für redis Ihnen dies nicht sagt.
Hlongmore
Interessant. Ja, es wird verwendet hmset. Ich werde das untersuchen. @hlongmore
Seperman
Kann es dennoch Bytes im Wörterbuch unterstützen?
ZettaCircl
11

Wenn Sie ein Python-Diktat in Redis speichern möchten, ist es besser, es als JSON-Zeichenfolge zu speichern.

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)

Beim Abrufen wird die Serialisierung mit json.loads durchgeführt

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

Was ist mit Typen (z. B. Bytes), die nicht von JSON-Funktionen serialisiert werden?

Sie können Encoder- / Decoderfunktionen für Typen schreiben, die von json-Funktionen nicht serialisiert werden können. z.B. Schreiben der Base64 / ASCII-Encoder / Decoder-Funktion für das Byte-Array.

Saji Xavier
quelle
Ich habe dies abgelehnt, weil einige Dikte nicht in JSON serialisiert werden können, z. B. Dikte mit einem Bytewert.
Tommy
1
Sie können eine Encoder / Decoder-Funktion (je nach Anforderung, z. B. Base64 / ASCII-Codierung) für die Typen schreiben, die standardmäßig nicht codiert / decodiert werden können.
Saji Xavier
@Tommy - Selbst wenn Sie hmset / hgetall verwenden, müssen Sie möglicherweise Typen codieren / decodieren, die von redis nicht unterstützt werden.
Saji Xavier
1
Nicht einverstanden mit "... letztere Operation ist O (N)." N ist die Anzahl der Felder, die Sie mit dem Schlüssel verknüpft haben. N SET / GET oder 1 HGET / HSET ist die gleiche Komplexität. Siehe: redis.io/commands/hmset Zeitlich gesehen sind HGET / HSET atomare Transaktionen und werden daher von REDIS schneller ausgeführt. Sie verschieben nur die Komplexität von Redis auf Python Code.
ZettaCircl
Der Vorteil von hmset ist die Möglichkeit, nur bestimmte Unterteile des Diktats abzurufen. Mit json verlieren wir das, also ist das so gut wie Gurke oder etwas anderes.
Jorge Leitao
10

Da die grundlegende Antwort bereits von anderen Personen gegeben wurde, möchte ich einige hinzufügen.

Im Folgenden finden Sie die Befehle REDISzum Ausführen grundlegender Operationen mit HashMap/Dictionary/MappingTypwerten.

  1. HGET => Gibt den Wert für den übergebenen Einzelschlüssel zurück
  2. HSET => Wert für den einzelnen Schlüssel setzen / aktualisieren
  3. HMGET => Gibt den Wert für übergebene Einzel- / Mehrfachschlüssel zurück
  4. HMSET => Werte für den Mehrfachschlüssel setzen / aktualisieren
  5. HGETALL => Gibt alle (Schlüssel-, Wert-) Paare in der Zuordnung zurück.

Im Folgenden sind ihre jeweiligen Methoden in der redis-pyBibliothek aufgeführt: -

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

Alle oben genannten Setter-Methoden erstellen das Mapping, falls es nicht vorhanden ist. Alle oben genannten Getter-Methoden lösen keine Fehler / Ausnahmen aus, wenn Mapping / Key in Mapping nicht vorhanden ist.

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

Ich hoffe, es macht die Dinge klarer.

Mangu Singh Rajpurohit
quelle
wie Sie den Schlüssel dynamisch machen können
ak3191
4

Ein anderer Weg, wie Sie sich der Sache nähern können:

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!

Ich habe es nicht auf Effizienz / Geschwindigkeit getestet.

Roberto
quelle
3

Der Befehl redis SET speichert eine Zeichenfolge und keine beliebigen Daten. Sie können versuchen, den Befehl redis HSET zu verwenden, um das Diktat als Redis-Hash mit so etwas wie zu speichern

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

Die Redis-Datentypen und Python-Datentypen stimmen jedoch nicht ganz überein. Python-Dicts können beliebig verschachtelt werden, aber für einen Redis-Hash muss Ihr Wert eine Zeichenfolge sein. Ein anderer Ansatz, den Sie wählen können, besteht darin, Ihre Python-Daten in Zeichenfolgen zu konvertieren und diese in Redis zu speichern

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

Wenn Sie die Zeichenfolge herausholen, müssen Sie sie analysieren, um das Python-Objekt neu zu erstellen.

Jesusaur
quelle
1
er kann seine Daten in json konvertieren und das Ergebnis in
redis
2

Man könnte in Betracht ziehen, MessagePack zu verwenden, das von redis unterstützt wird.

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

Mit msgpack-python und aioredis

Ohad Lahav
quelle
1

HMSET ist veraltet. Sie können HSET jetzt wie folgt mit einem Wörterbuch verwenden:

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
quelle
0

Versuchen Sie es mit rejson-py, das seit 2017 relativ neu ist. Schauen Sie sich diese Einführung an .

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
quelle
0

Wenn Sie nicht genau wissen, wie Sie Daten in Redis organisieren, habe ich einige Leistungstests durchgeführt, einschließlich der Analyse der Ergebnisse. Das von mir verwendete Diktat ( d ) hatte 437.084 Schlüssel (md5-Format) und die Werte dieser Form:

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

Erster Test (Einfügen von Daten in eine Redis-Schlüsselwertzuordnung):

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

Zweiter Test (Einfügen von Daten direkt in Redis-Schlüssel):

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

Wie Sie sehen können, müssen im zweiten Test nur 'info'-Werte analysiert werden, da der hgetall (Schlüssel) bereits ein Diktat zurückgibt, jedoch kein verschachteltes.

Und natürlich ist der erste Test das beste Beispiel für die Verwendung von Redis als Python-Diktat

Tavy
quelle