Redis学习03之 HASH
前一篇学习了String类型, 由于Redis的数据保存在内存中,查询方式非常块,像String类型可以存储浏览量,投票,文章点击等小量级的数据记录中,如果数据量超过百万级别使用简单的string映射关系会浪费大量的内存,此时Redis推荐使用另一种数据结构:HASH. 存储相同量级的数据Hash 消耗内存约String的四分之一,使用一种压缩存储,同时查询速度也并不差。 如果Redisk中有大量的keys, 使用key *会导致Redis hang,所以不清楚时不建议使用该命令。下面简单测试HASH的使用。
HASH 实例了KEY-VALUE的映射,和字符串类似,但Value是键值对, 根据Key可以快速找到Value, 无论有多少个键值对,查询时间是一样的,Python中的DICT就是HASH TABLE的实现。 Redis中的Hash可以存储2的32次方-1(约43亿)个键值对。
hash是一个string类型的field和value的映射表.一个key可对应多个field,一个field对应一个value。将一个对象存储为hash类型,较于每个字段都存储成string类型更能节省内存。新建一个hash对象时开始是用zipmap(又称为small hash)来存储的。这个zipmap其实并不是hash table,但是zipmap相比正常的hash实现可以节省不少hash本身需要的一些元数据存储开销。尽管zipmap的添加,删除,查找都是O(n)。
这里是因为Redis 的hash 对象有两种编码方式:
1. ziplist(2.6之前是zipmap)
2. hashtable
当哈希对象可以同时满足以下两个条件时, 哈希对象使用 ziplist 编码:
哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节;
哈希对象保存的键值对数量小于 512 个;
不能满足这两个条件的哈希对象需要使用 hashtable 编码。在Redis 内存优化时强烈建议使用HASH。
哈希类型中的命令及使用
配置值
HSET、HMSET 、HSETX
HSET – 设置值
HGET – 获取指定字段值
取值
HGET HMGET HGETALL
HGET – 获取指定字段值
HMGET – 返回多个字段值
HGETALL – 获取所有字段及值
自增
HINCRBY – 为指定字段值增加
HINCRBYFLOAT – 为指定字段值增加浮点数
其它
HDEL – 字段删除
HEXISTS – 判断字段是否存在
HKEYS – 返回所有字段
HLEN – 返回字段数量
HVALS – 返回所有字段值
127.0.0.1:6379> hset stu1 name Jack age 30 sex F (integer) 3 127.0.0.1:6379> hget stu1 name "Jack" 127.0.0.1:6379> hget stu1 age "30" 127.0.0.1:6379> hset stu1 id 1 (integer) 1 127.0.0.1:6379> hmget stu1 name sex 1) "Jack" 2) "F" 127.0.0.1:6379> hgetall stu1 1) "name" 2) "Jack" 3) "age" 4) "30" 5) "sex" 6) "F" 7) "id" 8) "1" 127.0.0.1:6379> hdel stu1 sex (integer) 1 127.0.0.1:6379> hmset stu2 name Tome id 2 OK 127.0.0.1:6379> hgetall stu1 1) "name" 2) "Jack" 3) "age" 4) "30" 5) "id" 6) "1" 127.0.0.1:6379> hgetall stu2 1) "name" 2) "Tome" 3) "id" 4) "2" 127.0.0.1:6379> hkeys stu1 1) "name" 2) "age" 3) "id" 127.0.0.1:6379> hkeys stu2 1) "name" 2) "id" 127.0.0.1:6379> hlen stu1 (integer) 3 127.0.0.1:6379> hvals stu1 1) "Jack" 2) "30" 3) "1" 127.0.0.1:6379> hincrby stu1 age 2 (integer) 32 127.0.0.1:6379> hget stu1 age "32"
案例
模拟像WEIBO,Twitter 上发布的链接一样,会自动转为短链接显示。这里有几个python文件
[root@MiWiFi-R2100-srv hash]# find . -name "*.py" -print -exec cat {} \; ./base36.py def base10_to_base36(number): alphabets = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" result = "" while number != 0 : number, i = divmod(number, 36) result = (alphabets[i] + result) return result or alphabets[0] ./shorty_url.py from base36 import base10_to_base36 ID_COUNTER = "ShortyUrl::id_counter" URL_HASH = "ShortyUrl::url_hash" class ShortyUrl: def __init__(self, client): self.client = client def shorten(self, target_url): new_id = self.client.incr(ID_COUNTER) short_id = base10_to_base36(new_id) self.client.hset(URL_HASH, short_id, target_url) return short_id def restore(self, short_id): return self.client.hget(URL_HASH, short_id) ./gethkeys.py import redis client = redis.Redis() fields = client.hkeys('ShortyUrl::url_hash') for name in fields: print(name.decode()) ./gethvals.py import redis client = redis.Redis() fields = client.hvals('ShortyUrl::url_hash') for name in fields: print(name.decode())
下面使用python CL命令行及调用py测试
[root@MiWiFi-R2100-srv hash]# python Python 2.7.5 (default, Nov 20 2015, 02:00:19) [GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from shorty_url import ShortyUrl >>> from redis import Redis >>> client = Redis(decode_responses=True) >>> shorty_url = ShortyUrl(client) >>> shorty_url.shorten('anbob.com') '1' >>> shorty_url.shorten('www.google.com/bolabolabola.html') '2' >>> shorty_url.restore("1") u'anbob.com' >>> shorty_url.restore("2") u'www.google.com/bolabolabola.html' >>> for i in range(30): ... shorty_url.shorten('www.anbob.com/arch/'+str(i)+'.html') ... 'Y' 'Z' '10' '11' '12' '13' '14' '15' ... ... '1M' '1N' '1O' '1P' '1Q' '1R' 127.0.0.1:6379> hgetall ShortyUrl::url_hash 70) "www.anbob.com/arch/1.html" 71) "10" 72) "www.anbob.com/arch/2.html" 73) "11" 74) "www.anbob.com/arch/3.html" 75) "12" 76) "www.anbob.com/arch/4.html" 77) "13" 78) "www.anbob.com/arch/5.html" 79) "14" 80) "www.anbob.com/arch/6.html" ... 114) "www.anbob.com/arch/23.html" 115) "1M" 116) "www.anbob.com/arch/24.html" 117) "1N" 118) "www.anbob.com/arch/25.html" [root@MiWiFi-R2100-srv hash]# python gethkeys.py 1 2 3 4 5 6 7 ... [root@MiWiFi-R2100-srv hash]# python gethvals.py anbob.com www.google.com/bolabolabola.html ... www.anbob.com/arch/0.html www.anbob.com/arch/1.html www.anbob.com/arch/2.html www.anbob.com/arch/3.html www.anbob.com/arch/4.html www.anbob.com/arch/5.html www.anbob.com/arch/6.html www.anbob.com/arch/7.html www.anbob.com/arch/8.html ...
也可用于存储json
>>> import json >>> import redis >>> client = redis.Redis() >>> client.hset('users','weejar', json.dumps({'id':1,'CNname':'张维照', 'blog':'www.anbob.com'})) 1L >>> client.hset('users','admin', json.dumps({'id':2,'CNname':'ADMIN', 'blog':'www.anbob.com/login'})) 1L >>> names = client.hkeys('users') >>> for p in names: ... print(p) ... admin weejar >>> for p in names: ... print(client.hget('users',p).decode()) ... {"blog": "www.anbob.com/login", "CNname": "ADMIN", "id": 2} {"blog": "www.anbob.com", "CNname": "\u5f20\u7ef4\u7167", "id": 1} >>> user_cnt=client.hlen('users') >>> print('there are {%s} users ' % user_cnt ) there are {2} users >>> if client.hexists('users','weejar'): ... client.hdel('users','weejar') ... 1 >>> client.hkeys('users') ['admin']
— over —
上一篇: Redis学习04之 List列表
对不起,这篇文章暂时关闭评论。