概述

Redis不是一个简单的键-值对存储,实际上它是一个数据结构服务器,支持不同类型的值。这意味着,在传统的键-值对存储你相关的字符串的键指向字符串的值,在Redis里值不仅限于简单的字符串,它可以支持更多的复杂数据结构。下面是Redis支持的所有的数据结构列表,在本教程里将分别地进行介绍:

  • 二进制安全的字符串
  • Lists:按照插入顺序排列的字符串元素的集合。从根本上说它们是 Linked Lists。
  • Sets:唯一项的集合,未排序的字符串元素
  • Sorted Sets:和Sets非常像,不同的是它的每个字符串元素都和一个浮点型的数字相关联,叫做score。元素通过它们的score进行排序,所以不像Sets,它可以检索一系列的元素(例如你可能像要前十条或后十条)
  • Hashes:它是由字段和值组成的map。字段和值都是字符串。这和Ruby和Python的hashes非常相似
  • Bit arrays(或简单的bitmaps):这能够使用特殊的命令,处理像bits数组的字符串值:你可以设置和清除单个bits,统计所有的bits设置为1,查找第一个设置的或非设置的bit,等等。
  • HyperLogLogs:这是一个概率性的数据结构,它是为了估计集合的基数。不要害怕,它比看起来更简单。稍后在这个教程的HyperLogLogs的部分见。

掌握数据类型是怎么工作的并不是非常简单,从 command reference 获取解决问题的命令用法,所以这篇文章是介绍Redis数据类型的速成班和它们最常见的模式。

所有的例子我们将使用 redis-cli 效用。这是一个简单又便利的命令行去发布命令连接Redis服务器。

Redis Keys

Redis keys是二进制安全的,这意味着你可以使用任意的二进制序列作为key,从像‘foo’这样的字符串到JPEG 文件的内容。空字符串也是有效的key。

关于key的一些规则:

  • 非常长的key并不好,例如一个1024字节的key,不仅内存不合理,而且因为数据中查找key也是非常昂贵的。即使手头的任务有很大的值要匹配,最好是去哈希它,特别是从内存和带宽的角度。
  • 非常短的key一般也不好。有一个小点‘u1000flw’作为一个key,不如写成‘user:1000:followers’。后者更具有可读性,前者更省空间。这要在这中间做一个权衡。
  • 试着坚持使用schema。例如”object-type:id“,就行像”user:1000“。点或破折号经常用于多词字段,像”comment:1234:reply.to“或”comment:1234:reply-to“。
  • key最大允许的长度是512MB。

Redis Strings

Redis 字符串类型是可以用键关联的最简单的值类型。它是Mamcached的唯一数据类型,所以它是新来者Redis很自然的支持类型。

由于Redis的键是字符串,当我们也用字符串作为值的时候,我们从一个字符串映射另一个字符串。字符串类型在大量的用例中都是有用的,像缓存HTML片段和页面。

让我们测试以下字符串类型,使用redis-cli

> set mykey somevalue
OK
> get mykey
"somevalue"

就像你看到的一样我们使用 SET 和 GET 可以设置和检索字符串值。注意 SET 会覆盖键中已经存在的值,在这个示例中key已经存在,即使这个键与非字符串的值相关联。所以 SET 执行一个任务。

值可以是各式各样的字符串,例如你可以存储一个jpeg的图像进一个key。一个值最大不能超过512MB。

SET 命令有有趣的选项,它提供附加的参数。例如,如果key已经存在就失败,或者如果key已经存在就成功。

> set mykey newval nx
(nil)
> set mykey newval xx
OK

即使字符串是Redis的基本值,你可以使用有趣的操作选项执行,例如,一个是原子增量

> set counter 100
OK
> incr counter
(integer) 101
> incr counter
(integer) 102
> incrby counter 50
(integer) 152

INCR 命令将字符串的值解析成integer,按一递增,并获取新设置的值。有其他的一些相似的命令像 INCRBY、 DECR 和 DECRBY 。在内部总是以稍微不同的方式执行相同的命令。

INCR 是原子的意味着什么?即使多个客户端使用INCR执行相同的key,也不会竞争。例如,client1和client2不会同时读取到‘10’,两个都增加到11,并设置新值为11。当其他的客户端没有执行相同命令的情况下,最终的值将保持12。

有一些操作字符串的命令。例如 GETSET 命令设置一个新值,返回原来的值。你可以使用这个命令,例如,如果你有个系统每次接收到访客就调用 INCR 增加Redis key。你可能想每小时收集一次这个信息,在不损伤增量的情况下。你可以 GETSET key,将Key 设置为0,并读取旧值。

为了减少延迟,一条命令执行设置或获取多个key是非常有用的。基于这种情况有 MSET 和 MGET 命令:

> mset a 10 b 20 c 30
OK
> mget a b c
1) "10"
2) "20"
3) "30"

当使用 MGET 的时候,Redis返回一个数组。

修改和查询key空间

有一些没有定义在特殊类型的命令,但是非常有助于操作key空间,因此可以用于任何的key。

例如 EXISTS 命令返回1或0,表示指定的key是否存在于数据库,当 DEL 命令删除key和相关的value,无论value是什么。

> set mykey hello
OK
> exists mykey
(integer) 1
> del mykey
(integer) 1
> exists mykey
(integer) 0

从上面的例子可以看出,EXITS命令返回1或0,取决于key是否存在。

有很多与key空间相关的命令,上面的两个命令和 TYPE 命令是最基本的命令,它返回指定key存储的value的类型。

> set mykey x
OK
> type mykey
string
> del mykey
(integer) 1
> type mykey
none

Redis 有效期:指定key的存活时间

在继续进行更复杂数据结构之前,我们需要讨论另一个特性,它不管key是什么类型,它叫Redis expires。基本上你可以对key设置一个超时时间,它限制key的存活时间。当指定是时间过后,key就会自动销毁,就好像用户调用DEL命令一样。

一些关于Redis expires的快讯:

  • 它可以设置秒和毫秒精度;
  • 然而,到期时间的分辨率总是1毫秒;
  • 关于有效期的信息被复制并保存到磁盘上,当Redis Server停止的时候仍然过期(这意味着Redis保存key的过期时间)

设置一个有效期非常简单:

> set key some-value
OK
> expire key 5
(integer) 1
> get key (immediately)
"some-value"
> get key (after some time)
(nil)

key在两个Get之间消失了,从第二次调用已经延迟超过了5秒钟。在上面的实例中,我们使用了EXPIRE为了设置超时时间(也可以设置不同的超时时间在存在的key上,像 PERSIST 可用于移除超时时间并永远的持久化key)。然而我们也可以使用其他的命令设置有效期。例如使用 SET 选项:

> set key 100 ex 10
OK
> ttl key
(integer) 9

上面的例子设置了一个value=100的字符串,有一个10秒的超时时间。然后 TTL 命令被调用,用于检查key剩下的存活时间。

为了用毫秒设置和检查有效期,检查PEXPIRE 和 PTTL 命令,和 SET 的全部选项。

Redis Lists

说明List数据类型之前最好先开始一些理论,List 术语经常被计算机技术人员用于不当的方式。例如 "Python Lists"不是名字的建议(Linked List),而是数组。

概括来讲,List只是一个一系列的有序元素:10,20,1,2,3是一个List。但是使用Array实现的List的属性和使用Linked List实现的List的属性有很大的不同。

Redis lists通过Linked List的实现。这意味着即使list里面有数以百万计的元素,在头部或者尾部添加新元素在一个常数时间内执行。使用 LPUSH 命令往有10个元素的list里添加一个新元素和往有1000万的list在头部添加一个元素速度一样。

缺点是什么?通过索引访问使用Array实现的List非常快,而访问使用Linked List实现的List不是很快。

Redis List使用Linked List实现。因为对于数据库来说关键是能够快速的添加元素到一个很长的List。另一个强大的优势,稍后你将看到,是Redis List可以在特定是时间保持长度不变。

当快速的访问大型集合的中间元素是非常重要的,有一个不同的数据结构可以使用,叫做sorted sets。Sorted sets将在本教程的后面介绍。

LPUSH 命令添加一个新元素到list,在左边, RPUSH 命令添加一个新元素到list,在右边。最后 LRANGE 命令从list提取范围内元素。

> rpush mylist A
(integer) 1
> rpush mylist B
(integer) 2
> lpush mylist first
(integer) 3
> lrange mylist 0 -1
1) "first"
2) "A"
3) "B"

注意 LRANGE 有两个索引,第一个和最后一个范围内的元素将被返回。索引都可以为负数,告诉Redis从结束开始计数:所以-1是最后一个,-2是list的倒数第二个元素,等等。

就像你看到的一样 RPUSH 在list的右边追加元素,LPUSH 在list的左边追加元素。

所有的命令都是可变参数的命令,意味着你可以在一次调用中自由的插入多个元素:

> rpush mylist 1 2 3 4 5 "foo bar"
(integer) 9
> lrange mylist 0 -1
1) "first"
2) "A"
3) "B"
4) "1"
5) "2"
6) "3"
7) "4"
8) "5"
9) "foo bar"

在Redis lists上有一个重要的定义是有pop元素的能力。pop元素是从list检索元素同时从list里消除元素的操作。你可以从左边或者右边pop元素,类似于往list里插入元素:

> rpush mylist a b c
(integer) 3
> rpop mylist
"c"
> rpop mylist
"b"
> rpop mylist
"a"

我们添加了3个元素并pop了3个元素,所以这一系列的命令之后list是空的并且没有元素可以pop。如果我们尝试pop另一个元素,这是我们得到的结果:

> rpop mylist
(nil)

Redis返回NULL值表示list里没有元素。

Lists对于很多任务都很有用,下面是两个典型地用例:

  • 记住用户发布到社交网络的最新更新。
  • 进程之间的通讯,使用 消费者-生产者 模式,生产者往list里添加,消费者消费那些项并执行操作。Redis有特殊的list命令使用例更可靠和更高效。

例如Ruby 类库 resque 和 sidekiq 在引擎下面使用Redis lists以便于实现后台作业。

流行的Twitter社交网络用户最新的微博保存的Redis lists。

一步一步的描述用例,想象你的首页展示你最新发布的照片分享到社交网络并且你想加速访问。

  • 每次用户上传它的照片,就将它的ID用 LPUSH 添加到一个list;
  • 当用户访问首页,我们使用 LRANGE 0 9 获取最新发布的的前10项。

在很多的用例中,我们仅仅想用lists保存最新的项,不管它们是什么:社交网络更新,日志,或者其他。

Redis允许用户使用list为固定集合,仅仅记录最新的N项并丢弃所有老的项使用 LTRIM 命令。

LTRIM 命令和 LRANGE 命令非常相似,但不是展示指定范围的元素,它设置这个range为新的list值。所有范围外的元素都将被移除。

示例会看的更清楚:

> rpush mylist 1 2 3 4 5
(integer) 5
> ltrim mylist 0 2
OK
> lrange mylist 0 -1
1) "1"
2) "2"
3) "3"

上面的 LTRIM 命令告诉Redis只展示从0到2元素,其他的将会被丢弃。这可让一个非常简单但有用的模式:做一个列表推送操作和一个列表裁剪操作,以增加新的元素和丢弃超额的元素。

LPUSH mylist
LTRIM mylist 0 999

上面的组合添加一个新元素并保持1000个最新的元素在List。使用 LRANGE 你可以访问头部的项而不需要记住老的数据。

注意:当 LRANGE 在技术上是一个 O 操作,访问小范围朝向头部或尾部是一个常数时间的操作。

Lists有一个特殊的特性,使它们适合实现队列,通常作为进程间通讯的中间块:阻塞操作。

想象一下,你想要一个进程把数据项放入一个list,并用另一个不同的进程做一些工作使用这些数据项。这是通常的 生产者/消费者 设置,并可以通过下面简单的步骤实现:

  • 往list里放入数据项,生产者叫 LPUSH.
  • 从list处理/提取数据项,消费者叫 RPOP.

可是有时候可能list是空的并没有事情要处理,所以 RPOP 返回NULL。在这种情况下消费者强制等待一些时间并再次用 RPOP 尝试。这叫polling(轮询),并且在这种情况下并不是好的方法因为它有几个缺点:

  1. 强制Redis和客户端执行无用的命令(当list是空的时候所有的请求都没有真正的工作,它们仅仅返回NULL)
  2. 添加了一个执行项的延迟,因为一个工作者收到一个NULL之后,等待一些时间。设置延迟小一些,我们等待调用 RPOP 之间的延迟更小,伴随着第一个放大的问题,也就是增加了更多的无用的调用。

所以Redis实现了命令 BRPOP 和 BLPOP,它们是 RPOP 和 LPOP 的如果list是空可以阻塞的版本:只要当一个新元素被添加到list中才会返回给调用者,或者达到用户指定的超时时间。

这是一个调用 BRPOP 的例子,我们应该用在工作上:

> brpop tasks 5
1) "tasks"
2) "do_something"

这表示:等待tasks列表的元素,但如果5秒没有元素可用之后就返回。

注意你可以设置0为超时时间,它表示永远等待元素,并且你可以指定多个list而不是一个,为了同时等待多个list,并当第一个list接收元素的时候得到通知。

关于 BRPOP ,要注意几个事情:

  1. 客户端以有序的方式被服务:第一个客户端阻塞等待一个list,当有一个元素被添加时第一个客户端先被调用。以此类推。
  2. 返回的值和 RPOP 返回的值不同:它是一个两个元素的数组,因为他还包含了key的名字,因为 BRPOP 和 BLPOP 能够同时阻塞式等待多个List。
  3. 如果达到超时时间,返回NULL。

关于List和阻塞选项有更多的事情你需要知道。我们建议你阅读下面的更多内容:

  • 可以构建安全队列和螺旋队列,使用 RPOPLPUSH.
  • 还有一个阻塞式命令,叫 BRPOPLPUSH.

Key的自动创建和删除(Automatic creation and removal of keys)

到目前为止,在我们的示例中从来没有在添加元素之前创建一个空的List,或者在List没有元素的时候移除List。这是Redis的责任:当List为空的时候删除key,或者在我们往key里面添加元素而元素不存在的时候创建它们,例如,用 LPUSH.

这个不特定于lists,它适用于所有的Redis数据类型 -- Sets,Sorted Sets 和 Hashes。

基本上我可以总结为三个规则:

  • 当我们往集合类型添加元素时,如果目标key不存在,在添加元素之前创建空的集合数据类型;
  • 当我们从集合类型移除元素时,如果value是空的,则key会自动的被删除;
  • 调用一个只读命令像 LLEN (它返回List的长度),或者用一个写入命令移除元素,使用一个空key,总是产生相同的结果,如果key持有一个空集合类型命令能够找到的类型。

第一个规则的示例:

> del mylist
(integer) 1
> lpush mylist 1 2 3
(integer) 3

然而我们不能执行已经存在的key的错误类型操作:

> set foo bar
OK
> lpush foo 1 2 3
(error) WRONGTYPE Operation against a key holding the wrong kind of value
> type foo
string

第二个规则的示例:

> lpush mylist 1 2 3
(integer) 3
> exists mylist
(integer) 1
> lpop mylist
"3"
> lpop mylist
"2"
> lpop mylist
"1"
> exists mylist
(integer) 0

所有的元素被pop完之后,key就不存在了。

第三个规则的示例:

> del mylist
(integer) 0
> llen mylist
(integer) 0
> lpop mylist
(nil)

Redis Hashes

Redis Hashes 怎么样使用field-value对精确的查看hash:

> 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

虽然Hashes是很方便的代表objects,实际上你可以添加到hash的字段的数量是不受限制的(除了可用内存),所以你可以在你的应用中以很多的方法使用hashes。

HMSET 命令设置hash的多个字段, 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

你可以在文档里找所有的hash命令列表。

值得注意的是小的hashes(也就是一些小值的元素)在内存里用一些特殊的编码,使得它们内存效率很高。

Redis Sets

Redis Sets是无序的字符串集合, SADD 命令添加一个新元素到set。也有可能做一些其他的操作针对于set像测试一个指定的元素是否存在,执行多个sets之间的合集,并集和不同,等等。

> sadd myset 1 2 3
(integer) 3
> smembers myset
1. 3
2. 1
3. 2

这里我添加了三个元素到myset并告诉Redis返回所有的元素。就像你看到的,它们没有排序--Redis在每一次调用的时候以任意的排序返回元素,因为没有协议与用户排序。

Redis有命令测试会员资格,例如检查指定的元素是否存在?

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

"3"是set的成员,而"30"不是。

Sets 有益于表达对象之间的关系。例如我们可以很容易使用sets实现tags。

一种简单的方式模拟这个问题是我们为每个对象想要的tag都有一个set。set包含与对象相关的tag的Id。

想象我们想标记新闻。如果我们的ID为1000的新闻用1,2,5和77标记,一个set用新闻项关联这些tag IDs:

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

然而有时我们也可能想有一个相反的关系:用指定的tag标记所有的新闻的列表:

> 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. 5
2. 1
3. 77
4. 2

注意:在这个例子里我们假定你有另外的数据类型,例如一个Redis hashes,它映射tag IDs到tag Name。

有其他非琐碎的操作,使用正确的命令仍然容易实现。例如我们想用tag 1,2,10和27一起所有的对象的列表。我们可以用 SINTER 命令做,它执行不同sets之间的交集。我们可以用:

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

交集不是唯一的操作执行,你还可以执行并集,差异,提取一个随机元素,等等。

提取一个元素的命令叫做 SPOP,且方便模拟某些问题。例如为了实现基于web的扑克游戏,你可能想用一个一个set代表你的甲板。想象我们用前缀表示(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 命令移除一个随机元素,将它返回给客户端,在这种情况下他是完美的操作。

然而如果我们直接对我们的甲板调用它,在游戏接下来的比赛我们需要再次填充甲板,这可能不是最理想的。所以开始,我们可以使set的拷贝存储进deck key到game:1:deck key。

这是有技巧的使用SUNIONSTORE,它通常执行多个set之间的并集并保持到另一个set。然而,由于单个set的并集是它本身,我可以拷贝mydesk:

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

一对jacks,不好。。。

现在是时候介绍set命令了,它提供set里元素的数量。这在集合论的背景下通常叫做cardinality 。所以Redis 命令叫做 SCARD 。

> scard game:1:deck
(integer) 47

数学计算方法:52-5=47;

如果你仅仅想从集合在获取随机的元素而不移除它,有一个适当的 SRANDMEMBER 命令。它的突出能力是可以返回重复的数据和不重复的数据。

Redis Sorted Sets

Sorted Sets是一个类似于混合Set和Hash的数据类型,像sets,sorted sets由唯一不重复的字符串元素组成,所以在某种意义上sorted set是一个set。

然而sets里的元素是没有顺序的,sorted set里的每个元素都关联一个浮点型的值,叫做score(这是为什么类型类似于hash,因为每个元素映射为一个值)。

另外,sorted sets里的元素都在顺序里。他们根据以下规则排序:

如果A和B是有不同的score的两个元素,如果A.score大于B.score,则A大于B。

如果正好A和B有相同的score,如果A的字符串大于B,则A大于B。A和B字符串不能相同因为sorted sets只有唯一的元素。

让我们开始于一个简单实例,添加一些选定的黑客名字作为sorted set元素,使用它们的生日作为score:

> zadd hackers 1940 "Alan Kay"
(integer) 1
> zadd hackers 1957 "Sophie Wilson"
(integer) 1
> zadd hackers 1953 "Richard Stallman"
(integer) 1
> zadd hackers 1949 "Anita Borg"
(integer) 1
> zadd hackers 1965 "Yukihiro Matsumoto"
(integer) 1
> zadd hackers 1914 "Hedy Lamarr"
(integer) 1
> zadd hackers 1916 "Claude Shannon"
(integer) 1
> zadd hackers 1969 "Linus Torvalds"
(integer) 1
> zadd hackers 1912 "Alan Turing"
(integer) 1

就像你看到的SADD类似于SADD,但是它有一个额外的score参数。ZADD是可变参数,所有你可以自由的指定多个score-value对,即使在上面的实例中没有使用。

根据它们的生日排序返回黑客列表不重要因为事实上它们已经排序了。

实现注意:Sorted sets通过双数据结构包含一个跳跃列表和一个hash表实现,所以每次我们添加一个元素Redis执行一个O操作。非常好,但是当我们请求排序的元素时,Redis根本没必要做任何工作,它已经排序了:

> zrange hackers 0 -1
1) "Alan Turing"
2) "Hedy Lamarr"
3) "Claude Shannon"
4) "Alan Kay"
5) "Anita Borg"
6) "Richard Stallman"
7) "Sophie Wilson"
8) "Yukihiro Matsumoto"
9) "Linus Torvalds"

注意:0和-1意思是从元素索引0到最后一个元素(这里的-1就像LRANGE命令的案例)。

如果我们想倒叙排列怎么走,从最年轻到最老?使用ZREVRANGE代替ZRANGE:

> zrevrange hackers 0 -1
1) "Linus Torvalds"
2) "Yukihiro Matsumoto"
3) "Sophie Wilson"
4) "Richard Stallman"
5) "Anita Borg"
6) "Alan Kay"
7) "Claude Shannon"
8) "Hedy Lamarr"
9) "Alan Turing"

使用WITHSCORES参数还可以返回scores:

> zrange hackers 0 -1 withscores
1) "Alan Turing"
2) "1912"
3) "Hedy Lamarr"
4) "1914"
5) "Claude Shannon"
6) "1916"
7) "Alan Kay"
8) "1940"
9) "Anita Borg"
10) "1949"
11) "Richard Stallman"
12) "1953"
13) "Sophie Wilson"
14) "1957"
15) "Yukihiro Matsumoto"
16) "1965"
17) "Linus Torvalds"
18) "1969"

Sorted sets远比这强大。他们可以在范围上操作。让我们获取出生早于1950的个人(包括)。我们使用ZRANGEBYSCORE命令去做:

> zrangebyscore hackers -inf 1950
1) "Alan Turing"
2) "Hedy Lamarr"
3) "Claude Shannon"
4) "Alan Kay"
5) "Anita Borg"

我们请求Redis返回score从负无穷到1950的所有元素(包括极端值)。

也有可能移除范围元素。让我们移除所有从1940年到1960年的黑客:

> zremrangebyscore hackers 1940 1960
(integer) 4

ZREMRANGEBYSCORE或许不是最好的命令名字,但是它非常有用,并返回移除元素的数量。

另外非常有用的操作定义soreted set元素是get-rank操作。可能访问排序元素的元素位置是什么。

> zrank hackers "Anita Borg"
(integer) 4

ZREVRANK命令也是可用的以便于获得rank,考虑到元素排序降序的方式。

最新的Redis2.8版本,一些新特性的介绍允许字典序的获取范围,假定sorted set里的元素使用相同的score插入。

使用字典序的主要命令操作是ZRANGEBYLEX,ZREVRANGEBYLEX,ZREMRANGEBYLEX和ZLEXCOUNT。

例如,我们再次添加我们的著名黑客列表,但是这次给所有的元素使用0score:

> zadd hackers 0 "Alan Kay" 0 "Sophie Wilson" 0 "Richard Stallman" 0
"Anita Borg" 0 "Yukihiro Matsumoto" 0 "Hedy Lamarr" 0 "Claude Shannon"
0 "Linus Torvalds" 0 "Alan Turing"

因为scoreted set排序规则,他们已经字典序的排序了:

> zrange hackers 0 -1
1) "Alan Kay"
2) "Alan Turing"
3) "Anita Borg"
4) "Claude Shannon"
5) "Hedy Lamarr"
6) "Linus Torvalds"
7) "Richard Stallman"
8) "Sophie Wilson"
9) "Yukihiro Matsumoto"

使用ZRANGEBYLEX我们可以访问字典的范围:

> zrangebylex hackers [B [P
1) "Claude Shannon"
2) "Hedy Lamarr"
3) "Linus Torvalds"

范围可以是包含或不包含(根据第一个字符),无限字符串和负无限要分别使用+和-指定。查看文档获取更多信息。

这个特性非常重要因为它可让我们使用sorted sets作为通用索引。例如,如果你想通过128位的无符号整型参数索引元素,你需要的全部操作是使用相同的score,由128未的大字节码组成的8位前缀和元素一起添加进scorted set。因为数字是大字节码,当字典序的排序时,通常用数字排序,你可以在128位范围内访问,并且可以丢弃前缀获取元素的值。

如果你想查看这个特性更完整的实例,查看Redis autocomplete demo。

在进行下一个话题之前最后一个需要注意的。Sorted sets的scores可以随时更新。只调用ZADD应对已经存在在sorted set的元素京用O时间更新score。同样的,sorted sets适用于大量的更新。

因为这个典型的通用案例是排行榜。典型的应用是Facebook游戏结合玩家的能力通过高分排序,加上get-rank操作,以便在排行榜展示top-N用户和用户影响力。

Bitmaps

Bitmaps不是一个真实数据类型,是一组定义在字符串类型面向位的操作。因为字符串是二进制安全的blogs并且他们最大长度是512MB,他们适合建立2^32个不同位。

Bit操作分为两组:不变数量单个bit操作,像设置一个bit为1或0,或者获取它的值操作,例如在指定范围的bits里计算数量(如人口统计)。

bitmaps最有用的是他们经常在存储信息时提供急速空间保存。例如在一个系统里不同用户通过递增的user Ids代表,可以记录单个bit信息,40亿只用512MB内存。

Bits使用SETBIT和GETBIT命令设置和获取:

> setbit key 10 1
(integer) 1
> getbit key 10
(integer) 1
> getbit key 11
(integer) 0

其他值得注意的特性

Redis API里有其他重要的东西不能在这个文档里深入探究,但值得你注意:

  • 可以递增的生产大集合的key空间
  • 可以运行Laa脚本服务端
  • Redis还是一个发布-订阅服务。

了解更多

这个教程没办法完成,只是覆盖了基础API。阅读命令手册去了解更多。


多谢你的阅读!


原创文章,转载请注明出处:转载自Redis中文网 - Redis数据类型



最新文章

Redis最新文章

Redis最热文章