探究Redis 04:哈希表与集合

Redis哈希表(Hashes)

Redis中的哈希表数据类型和很多编程语言的实现类似,通过键值对记录数据:

> hmset user:1000 username antirez birthyear 1977 verified 1
OK
> hget user:1000 username
"antirez"
> hget user:1000 birthyear
"1977"
> hgetall user:1000
1) "username"
2) "antirez"
3) "birthyear"
4) "1977"
5) "verified"
6) "1"

尽管哈希表是一种方便的存储对象属性的数据类型。但由于在Redis中,向哈希表添加键值对并无数量限制(除了占用内存外),它可以在各种应用场景发挥作用。

HMSET命令可以设置多个哈希表字段, 而HGET可以获取某个字段的值.HMGET类似HGET但可以支持一次返回多个字段内容:

> hmget user:1000 username birthyear no-such-field
1) "antirez"
2) "1977"
3) (nil)

也有一些命令只操作哈希表中的某个字段,例如:HINCRBY:

> hincrby user:1000 birthyear 10
(integer) 1987
> hincrby user:1000 birthyear 10
(integer) 1997

在此可以查看Redis哈希表支持的全部命令文档

一个值得提示的情况是:在只有几个小字段组成的哈希表实现中,Redis使用了特殊的存储编码。使得在此场景下,哈希表的内存利用率得到了显著提升。

Redis集合(Sets)

Redis集合用于记录一组无序的Redis字符串。通过SADD命令,可以向集合中添加元素。同时,Redis也支持一系列其他操作,如:检测元素是否在集合中, 计算两个集合的交集、并集、差集等。

> sadd myset 1 2 3
(integer) 3
> smembers myset
1) "b"
2) "a"
3) "c"

在上面的示例中,我们向集合添加了三个元素,并操作Redis返回全部集合元素。你可能已经观察到Redis的返回元素是无序的。事实上,使用集合时应当注意,Redis在每次调用命令获取集合元素时,返回内容都无法保证顺序。

Redis可以通过以下命令检测元素是否已在集合中存在:

> sismember myset 3
(integer) 1
> sismember myset 30
(integer) 0

"3"已在集合中, 而"30"不在。

集合通常用于表达对象之间的关联关系。例如:通过集合可以很容易地实现标签功能。实现标签模型需要为每个标记对象创建一个集合,用于记录标记对象与标签ID的关联关系。比如给新闻文章打标签时,如果需要将ID为1000的文章使用标签1、2、5和77进行标记,则可以使用集合记录标签与文章的关联:

> sadd news:1000:tags 1 2 5 77
(integer) 4

我们也许还需要记录逆向关联,记录标签和关联文章集合的绑定关系:

> sadd tag:1:news 1000
(integer) 1
> sadd tag:2:news 1000
(integer) 1
> sadd tag:5:news 1000
(integer) 1
> sadd tag:77:news 1000
(integer) 1

此时获取文章对应的标签十分容易:

> smembers news:1000:tags
1) "1"
2) "2"
3) "5"
4) "77"

这里需要注意的是,我们在上面示例中还假设存在另一个数据结构例如哈希表, 用来存储标签ID与标签名称的对应关系。

有了集合,一些其他类型的操作很容易实现。例如:我们需要获取同时包含标签1、2、10和27的文章列表。通过SINTER命令很容易实现,此命令可以计算各集合的交集结果:

> sinter tag:1:news tag:2:news tag:10:news tag:27:news
... results here ...

除此之外,你也可以对集合数据进行并集计算,差集计算,或抽取随机元素等操作。

抽取元素可以使用SPOP命令,在某些应用场景下十分方便。例如,为了实现某种网络扑克游戏,您可能需要用集合来表示不同花色。假设我们对(c)lubs,(d)iamonds,(h)earts,(s)pades四个花色使用字符前缀表示:

>  sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK
   D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3
   H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6
   S7 S8 S9 S10 SJ SQ SK
   (integer) 52

现在我们要为每位成员发5张牌。使用SPOP命令可以随机移除一个集合元素,并返回给客户端,正好适用以上场景。

然而,如果直接使用此命令,在下一轮发牌时,需要再次填充花色,十分低效。为解决此问题,我们可以提前将一副牌的数据存储到一个固定的Redis集合deck中,每次重新开始游戏时,拷贝deck到一个新集合:game:1:deck

以上场景可以通过SUNIONSTORE命令实现,它的功能是将一个或多个集合内容合并后存储到一个新的集合。例如:

> sunionstore game:1:deck deck
(integer) 52

之后,我们就可以给第一个玩家发牌了:

> spop game:1:deck
"C6"
> spop game:1:deck
"CQ"
> spop game:1:deck
"D1"
> spop game:1:deck
"CJ"
> spop game:1:deck
"SJ"

此时,我们介绍一个新的集合命令SCARD,你可以通过此命令获取集合中元素的数量(基数)。

> scard game:1:deck
(integer) 47

此时,计算一下,还剩52 - 5 = 47张牌

另一个典型场景是双色球抽奖。其过程需要从一堆标有数字的小球中随机抽取几个球作为中奖号码。此时,使用SRANDMEMBER命令可以方便的实现功能。该命令支持从集合中一次性随机抽取一定数量的元素,同时支持通过参数控制:允许重复返回元素。(一个帮助理解重复返回元素的场景是:抽奖时,将每次抽取的小球重新放回,之后的动作可能重复抽到同一个小球的情况)

redis> SADD myset one two three
(integer) 3
redis> SRANDMEMBER myset
"three"
redis> SRANDMEMBER myset 2
1) "one"
2) "two"
redis> SRANDMEMBER myset -5
1) "one"
2) "two"
3) "two"
4) "one"
5) "one"

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容