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

답변:


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
단순히 dict가 아닌 중첩 된 데이터 구조 인 경우, 예를 들어 일부 배열 등을 포함하는 경우 json.dumps()문자열 로 쓰기를 사용 하여 데이터 json.loads()를 직렬화하고 파이썬 데이터 구조로 역 직렬화하기 위해 redis 사용자로부터 검색 한 후
andilabs

7
json.dumps()그리고 json.loads()당신이 당신의 사전 키는 항상 문자열 인 괜찮 경우에만 작동합니다. 그렇지 않은 경우 피클 사용을 고려할 수 있습니다.
ryechus

6
json은 바이트와 호환되지 않으므로 json serilization은 글로벌 솔루션이 아닙니다. 예를 들어 바이트 값이있는 dict가 있으면 작동하지 않습니다.
Tommy

8
참고로에 대한 문서는 hmset이를 알려주지 않지만 빈 dict를 저장하려고하면 DataError가 발생합니다.
hlongmore

1
@Pradeep 우리가 키를 동적으로 만드는 방법. 내가 키 동적을 만들 수있는 방법 있도록 데이터는 매 15 분 삽입하기 겠지
ak3191

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
이것은 사실이지만 읽기 및 쓰기 속도에 따라 심각한 오버 헤드가 추가 될 수 있습니다. 산 세척은 느린 작업입니다
Tommy

1
이 사용자 입력을 사용하는 경우 서버가 있습니다 원격 코드 exection하는 경향이있다 , 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

파이썬 유형을 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
참고로 RedisWorks는 hmset변수를 dict로 설정하면 내부적으로 사용 하므로 빈 사전을 허용하지 않기 root.something = {}때문에 DataError hmset가 발생합니다. 나는 redis에 대한 문서가 이것을 알려주지 않기 때문에 이것을 언급합니다.
hlongmore

흥미 롭군. 예, hmset. 나는 이것을 조사 할 것이다. @hlongmore
Seperman

그러나 여전히 사전에서 바이트를 지원할 수 있습니까?
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

11

redis에 파이썬 사전을 저장하려면 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 인코더 / 디코더 함수 작성.


예를 들어 바이트 값이있는 dicts와 같이 일부 dicts를 JSON으로 직렬화 할 수 없기 때문에 이것을 거부했습니다.
Tommy

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 Time-wise, HGET / HSET은 원자 트랜잭션이므로 REDIS에 의해 더 빠르게 수행됩니다. Redis에서 Python Code로 복잡성을 이동하고 있습니다.
ZettaCircl

hmset의 장점은 dict의 특정 하위 부분 만 검색 할 수 있다는 것입니다. json으로 우리는 그것을 잃어 버리므로 이것은 피클이나 다른 것만 큼 좋습니다.
Jorge Leitao 19:51에

5

redis가 보증하는 MessagePack 사용을 고려할 수 있습니다 .

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

사용 msgpack - 파이썬aioredis을


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 명령을 사용하여 dict를 다음과 같은 redis 해시로 저장할 수 있습니다.

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

그러나 redis 데이터 유형과 python 데이터 유형은 일치하지 않습니다. Python dicts는 임의로 중첩 될 수 있지만 redis 해시는 값이 문자열이어야합니다. 취할 수있는 또 다른 접근 방식은 파이썬 데이터를 문자열로 변환하고이를 redis에 저장하는 것입니다.

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

그런 다음 문자열을 꺼내면 파이썬 객체를 다시 생성하기 위해 구문 분석해야합니다.


1
그는 자신의 데이터를 json으로 변환하고 결과를 redis에 저장할 수 있습니다.
Narcisse Doudieu Siewe

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 중단 경고에 대한합니다.
Saransh Singh

0

2017 년 이후 비교적 새로운 rejson-py 를 사용 해보세요 . 이 소개를 보세요 .

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

보시다시피 두 번째 테스트에서는 hgetall (key)가 이미 dict를 반환하지만 중첩 된 것은 아니기 때문에 'info'값만 구문 분석해야합니다.

물론 Redis를 파이썬의 딕셔너리로 ​​사용하는 가장 좋은 예는 첫 번째 테스트입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.