第二章 Redis数据类型以及操作

目录

第二章 Redis 数据类型及操作

2.2 strings 类型及操作

2.3 hashes类型以及操作

2.4 lists类型以及操作

2.5 sets类型以及操作

2.6 sorted sets 类型及操作


第二章 Redis 数据类型及操作

 2.1 前言

Redis 的作者 antirez(Salvatore Sanfilippo)曾经发表了一篇名为 Redis 宣言(Redis Manifesto) 的文章,文中列举了 Redis 的七个原则,以向大家阐明 Redis 的思想。

 

1、Redis 是一个操作数据结构的语言工具,它提供基于 TCP  的协议以操作丰富的数据结构。在 Redis 中,数据结构这个词的意义不仅表示在某种数据结构上的操作,更包括了结构本身及这些操作的时间空间复杂度。

 

2、Redis 定位于一个内存数据库,正是由于内存的快速访问特性,才使得 Redis  能够有如此高的性能,才使得 Redis 能够轻松处理大量复杂的数据结构,Redis 会尝试其它的存储方面的选择,但是永远不会改变它是一个内存数据库的角色。

 

3、Redis 使用基础的 API 操作基础的数据结构,Redis 的 API 与数据结构一样,都是一些最基础的元素,你几乎可以将任何信息交互使用此 API 格式表示。作者调侃说,如果有其它非人类的智能生物存在,他们也能理解 Redis 的 API。因为它是如此的基础。

 

4、Redis 有着诗一般优美的代码,经常有一些不太了解 Redis 有的人会建议 Redis 采用一些其它人的代码,以实现一些 Redis 未实现的功能,但这对我们来说就像是非要给《红楼梦》接上后四十回一样。

 

5、Redis 始终避免复杂化,我们认为设计一个系统的本质,就是与复杂化作战。我们不会为了一个小功能而往源码里添加上千行代码,解决复杂问题的方法就是让复杂问题永远不要提复杂的问题。

 

6、Redis 支持两个层成的 API,第一个层面包含部分操作 API,但它支持用于分布式环境下的 Redis。第二个层面的 API 支持更复杂的 multi-key 操作。它们各有所长,但是我们不会推出两者都支持的 API,但我们希望能够提供实例间数据迁移的命令,并执行 multi-key 操作。

 

7、我们以优化代码为乐,我们相信编码是一件辛苦的工作,唯一对得起这辛苦的就是去享受它。如果我们在编码中失去了乐趣,那最好的解决办法就是停下来。我们决不会选择让Redis 不好玩的开发模式。

 

Redis 的作者 antirez 曾笑称 Redis 为一个数据结构服务器(data structures server),我认为这是一个非常准确的表述,Redis 的所有功能就是将数据以其固有的几种结构来保存,并提供给用户操作这几种结构的接口。本文将介绍 Redis 支持的各种数据类型及其操作接口。

 

2.2 strings 类型及操作

string 是最简单的类型,你可以理解成与 Memcached 是一模一样的类型,一个 key 对应一个

value,其上支持的操作与 Memcached 的操作类似。但它的功能更丰富。

 

string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据,比如 jpg 图片或者序列化的对象。从内部实现来看其实 string 可以看作 byte 数组,最大上限是 1G 字节,下面是

string 类型的定义:

struct sdshdr

{ long len;

long free;

char buf[];

};

len 是 buf 数组的长度。

free 是数组中剩余可用字节数,由此可以理解为什么 string 类型是二进制安全的了,因为它本质上就是个 byte 数组,当然可以包含任何数据了

buf 是个 char 数组用于存贮实际的字符串内容,其实 char 和 c#中的 byte 是等价的,都是一个字节。

另外 string 类型可以被部分命令按 int 处理.比如 incr 等命令,如果只用 string 类型,redis 就可以被看作加上持久化特性的 memcached。当然 redis 对 string 类型的操作比 memcached 还是多很多的,具体操作方法如下:

 

2.2.1 set

设置 key 对应的值为 string 类型的 value。

例如我们添加一个 name= HongWan 的键值对,可以这样做:

redis 127.0.0.1:6379> set name HongWan

OK

redis 127.0.0.1:6379>

 

2.2.2 setnx

设置 key 对应的值为 string 类型的 value。如果 key 已经存在,返回 0,nx 是 not exist 的意思。例如我们添加一个 name= HongWan_new 的键值对,可以这样做:

redis 127.0.0.1:6379> setnx name HongWan_new

(integer) 0

redis 127.0.0.1:6379> get name "HongWan"

redis 127.0.0.1:6379>

 

2.2.3 setex

设置 key 对应的值为 string 类型的 value,并指定此键值对应的有效期。

例如我们添加一个 haircolor= red 的键值对,并指定它的有效期是 10 秒,可以这样做:

redis 127.0.0.1:6379> setex haircolor 10 red

OK

redis 127.0.0.1:6379> get haircolor "red"

redis 127.0.0.1:6379> get haircolor

(nil)

redis 127.0.0.1:6379>

2.2.4 setrange

设置指定 key 的 value 值的子字符串。

例如我们希望将 HongWan 的 126 邮箱替换为 gmail 邮箱,那么我们可以这样做:

redis 127.0.0.1:6379> get name "[email protected]"

redis 127.0.0.1:6379> setrange name 8 gmail.com

(integer) 17

redis 127.0.0.1:6379> get name "HongWan@gmail.com"

redis 127.0.0.1:6379>

其中的 8 是指从下标为 8(包含 8)的字符开始替换

2.2.5 mset

一次设置多个 key 的值,成功返回 ok 表示所有的值都设置了,失败返回 0 表示没有任何值被设置。

redis 127.0.0.1:6379> mset key1 HongWan1 key2 HongWan2

OK

redis 127.0.0.1:6379> get key1 "HongWan1"

redis 127.0.0.1:6379> get key2

"HongWan2"

redis 127.0.0.1:6379>

2.2.6 msetnx

一次设置多个 key 的值,成功返回 ok 表示所有的值都设置了,失败返回 0 表示没有任何值被设置,但是不会覆盖已经存在的 key。

redis 127.0.0.1:6379> get key1 "HongWan1"

redis 127.0.0.1:6379> get key2 "HongWan2"

redis 127.0.0.1:6379> msetnx key2 HongWan2_new key3 HongWan3 (integer) 0

redis 127.0.0.1:6379> get key2 "HongWan2"

redis 127.0.0.1:6379> get key3

(nil)

可以看出如果这条命令返回 0,那么里面操作都会回滚,都不会被执行。

2.2.7 get

获取 key 对应的 string 值,如果 key 不存在返回 nil。

例如我们获取一个库中存在的键 name,可以很快得到它对应的 value

redis 127.0.0.1:6379> get name

"HongWan"

redis 127.0.0.1:6379>

 

2.2.8 getset

设置 key 的值,并返回 key 的旧值。

redis 127.0.0.1:6379> get name "HongWan"

redis 127.0.0.1:6379> getset name HongWan_new

"HongWan"

redis 127.0.0.1:6379> get name "HongWan_new"

redis 127.0.0.1:6379>

接下来我们看一下如果 key 不存的时候会什么样儿?

redis 127.0.0.1:6379> getset name1 aaa

(nil)

redis 127.0.0.1:6379>

可见,如果 key 不存在,那么将返回 nil

2.2.9 getrange

 

获取指定 key 的 value 值的子字符串。具体样例如下:

redis 127.0.0.1:6379> get name "[email protected]"

redis 127.0.0.1:6379> getrange name 0 6

"HongWan"

redis 127.0.0.1:6379>

字符串左面下标是从 0 开始的

redis 127.0.0.1:6379> getrange name -7 -1

"126.com"

redis 127.0.0.1:6379>

字符串右面下标是从-1 开始的

redis 127.0.0.1:6379> getrange name 7 100

"@126.com"

redis 127.0.0.1:6379>

当下标超出字符串长度时,将默认为是同方向的最大下标

2.2.10 mget

一次获取多个 key 的值,如果对应 key 不存在,则对应返回 nil。具体样例如下:

redis 127.0.0.1:6379> mget key1 key2 key3

  1. "HongWan1"
  2. "HongWan2"
  3. (nil)

redis 127.0.0.1:6379>

 

key3 由于没有这个键定义,所以返回 nil。

2.2.11 incr

对 key 的值做加加操作,并返回新的值。注意 incr 一个不是 int 的 value 会返回错误,incr 一个不存在的 key,则设置 key 为 1

redis 127.0.0.1:6379> set age 20 OK

redis 127.0.0.1:6379> incr age

(integer) 21

redis 127.0.0.1:6379> get age "21"

redis 127.0.0.1:6379>

2.2.12 incrby

同 incr 类似,加指定值 ,key 不存在时候会设置 key,并认为原来的 value 是 0

redis 127.0.0.1:6379> get age "21"

redis 127.0.0.1:6379> incrby age 5

(integer) 26

redis 127.0.0.1:6379> get name "[email protected]"

redis 127.0.0.1:6379> get age "26"

redis 127.0.0.1:6379>

2.2.13 decr

对 key 的值做的是减减操作,decr 一个不存在 key,则设置 key 为-1

redis 127.0.0.1:6379> get age "26"

redis 127.0.0.1:6379> decr age

(integer) 25

redis 127.0.0.1:6379> get age "25"

redis 127.0.0.1:6379>

2.2.14 decrby

同 decr,减指定值。

redis 127.0.0.1:6379> get age "25"

redis 127.0.0.1:6379> decrby age 5

(integer) 20

redis 127.0.0.1:6379> get age "20"

redis 127.0.0.1:6379>

decrby 完全是为了可读性,我们完全可以通过 incrby 一个负值来实现同样效果,反之一样

redis 127.0.0.1:6379> get age "20"

redis 127.0.0.1:6379> incrby age -5

(integer) 15

redis 127.0.0.1:6379> get age "15"

redis 127.0.0.1:6379>

2.2.15 append

给指定 key 的字符串值追加 value,返回新字符串值的长度。例如我们向 name 的值追加一个@126.com 字符串,那么可以这样做:

redis 127.0.0.1:6379> append name @126.com

(integer) 15

redis 127.0.0.1:6379> get name

"[email protected]"

redis 127.0.0.1:6379>

2.2.16 strlen

取指定 key 的 value 值的长度。

redis 127.0.0.1:6379> get name "HongWan_new"

redis 127.0.0.1:6379> strlen name

(integer) 11

redis 127.0.0.1:6379> get age "15"

redis 127.0.0.1:6379> strlen age

(integer) 2

redis 127.0.0.1:6379> 

 

2.3 hashes类型以及操作

Redis hash 是一个 string 类型的 field 和 value 的映射表.它的添加、删除操作都是 O(1()平均)。hash 特别适合用于存储对象。相较于将对象的每个字段存成单个 string 类型。将一个对象存储在 hash 类型中会占用更少的内存,并且可以更方便的存取整个对象。省内存的原因是新建一个 hash 对象时开始是用 zipmap(又称为 small hash)来存储的。这个 zipmap 其实并不是 hash table,但是 zipmap 相比正常的 hash 实现可以节省不少 hash 本身需要的一些元数据存储开销。尽管 zipmap 的添加,删除,查找都是 O(n),但是由于一般对象的 field 数量都不太多。所以使用 zipmap 也是很快的,也就是说添加删除平均还是 O(1)。如果 field 或者 value 的大小超出一定限制后,Redis 会在内部自动将 zipmap 替换成正常的 hash 实现.  这个限制可以在配置文件中指定:

hash-max-zipmap-entries 64 #配置字段最多 64 个

hash-max-zipmap-value 512 #配置 value 最大为 512 字节

2.3.1 hset

设置 hash field 为指定值,如果 key 不存在,则先创建。

redis 127.0.0.1:6379> hset myhash field1 Hello

(integer) 1

redis 127.0.0.1:6379>

2.3.2 hsetnx

设置 hash field 为指定值,如果 key 不存在,则先创建。如果 field 已经存在,返回 0,nx 是not exist 的意思。

redis 127.0.0.1:6379> hsetnx myhash field "Hello"

(integer) 1

redis 127.0.0.1:6379> hsetnx myhash field "Hello"

(integer) 0

redis 127.0.0.1:6379> 

2.3.3 hmset

同时设置 hash 的多个 field。

redis 127.0.0.1:6379> hmset myhash field1 Hello field2 World

OK

redis 127.0.0.1:6379>

2.3.4 hget

获取指定的 hash field。

redis 127.0.0.1:6379> hget myhash field1

"Hello"

redis 127.0.0.1:6379> hget myhash field2 "World"

redis 127.0.0.1:6379> hget myhash field3

(nil)

redis 127.0.0.1:6379>

由于数据库没有 field3,所以取到的是一个空值 nil

2.3.5 hmget

获取全部指定的 hash filed。

redis 127.0.0.1:6379> hmget myhash field1 field2 field3

  1. "Hello"
  2. "World"
  3. (nil)

redis 127.0.0.1:6379>  

2.3.6 hincrby

指定的 hash filed 加上给定值。

redis 127.0.0.1:6379> hset myhash field3 20

(integer) 1

redis 127.0.0.1:6379> hget myhash field3 "20"

redis 127.0.0.1:6379> hincrby myhash field3 -8

(integer) 12

redis 127.0.0.1:6379> hget myhash field3

"12"

redis 127.0.0.1:6379>

2.3.7 hexists

测试指定 field 是否存在。

redis 127.0.0.1:6379> hexists myhash field1

(integer) 1

redis 127.0.0.1:6379> hexists myhash field9

(integer) 0

redis 127.0.0.1:6379>  

2.3.8 hlen

返回指定 hash 的 field 数量。

redis 127.0.0.1:6379> hlen myhash

(integer) 4

redis 127.0.0.1:6379>

通过上例可以看到 myhash 中有 4 个 field。

2.3.9 hdel

返回指定 hash 的 field 数量。

redis 127.0.0.1:6379> hlen myhash

(integer) 4

redis 127.0.0.1:6379> hdel myhash field1

(integer) 1

redis 127.0.0.1:6379> hlen myhash

(integer) 3

redis 127.0.0.1:6379>

2.3.10 hkeys

返回 hash 的所有 field。

redis 127.0.0.1:6379> hkeys myhash

  1. "field2"
  2. "field"
  3. "field3"

redis 127.0.0.1:6379> 

2.3.11 hgetall

获取某个 hash 中全部的 filed 及 value。                                                                                                                                                                                                                                                                                                                                                                                    

redis 127.0.0.1:6379> hgetall myhash

  1. "field2"
  2. "World"
  3. "field"
  4. "Hello"
  5. "field3" 6) "12"

redis 127.0.0.1:6379>

2.3.12 havls

返回 hash 的所有 value。

redis 127.0.0.1:6379> hvals myhash

  1. "World"
  2. "Hello" 3) "12"

redis 127.0.0.1:6379>  

2.4 lists类型以及操作

list 是一个链表结构,主要功能是 push、pop、获取一个范围的所有值等等,操作中 key 理解为链表的名字。

Redis 的 list 类型其实就是一个每个子元素都是 string 类型的双向链表。链表的最大长度是(2 的 32 次方)。我们可以通过 push,pop 操作从链表的头部或者尾部添加删除元素。这使得 list 既可以用作栈,也可以用作队列。

有意思的是 list 的 pop 操作还有阻塞版本的,当我们[lr]pop 一个 list 对象时,如果 list 是空, 或者不存在,会立即返回 nil。但是阻塞版本的 b[lr]pop 可以则可以阻塞,当然可以加超时时间,超时后也会返回 nil。为什么要阻塞版本的 pop 呢,主要是为了避免轮询。举个简单的例子如果我们用 list 来实现一个工作队列。执行任务的 thread 可以调用阻塞版本的 pop 去获取任务这样就可以避免轮询去检查是否有任务

存在。当任务来时候工作线程可以立即返回, 也可以避免轮询带来的延迟。说了这么多,接下来看一下实际操作的方法吧:

2.4.1 lpush

在 key 对应 list 的头部添加字符串元素

redis 127.0.0.1:6379> lpush mylist "world"

(integer) 1

redis 127.0.0.1:6379> lpush mylist "hello" (integer) 2

redis 127.0.0.1:6379> lrange mylist 0 -1

  1. "hello"
  2. "world"

redis 127.0.0.1:6379>

2.4.2 rpush

在 key 对应 list 的尾部添加字符串元素

redis 127.0.0.1:6379> rpush mylist2 "hello" (integer) 1

redis 127.0.0.1:6379> rpush mylist2 "world"

(integer) 2

redis 127.0.0.1:6379> lrange mylist2 0 -1

  1. "hello"
  2. "world"

redis 127.0.0.1:6379>

2.4.3 linsert

在 key 对应 list 的特定位置之前或之后添加字符串元素

redis 127.0.0.1:6379> rpush mylist3 "hello" (integer) 1

redis 127.0.0.1:6379> rpush mylist3 "world" (integer) 2

redis 127.0.0.1:6379> linsert mylist3 before "world" "there"

(integer) 3

redis 127.0.0.1:6379> lrange mylist3 0 -1

  1. "hello"
  2. "there"
  3. "world"

redis 127.0.0.1:6379>

2.4.4 lset

设置 list 中指定下标的元素值(下标从 0 开始)

redis 127.0.0.1:6379> rpush mylist4 "one" (integer) 1

redis 127.0.0.1:6379> rpush mylist4 "two" (integer) 2

redis 127.0.0.1:6379> rpush mylist4 "three" (integer) 3

redis 127.0.0.1:6379> lset mylist4 0 "four"

OK

redis 127.0.0.1:6379> lset mylist4 -2 "five"

OK

redis 127.0.0.1:6379> lrange mylist4 0 -1

  1. "four"
  2. "five"
  3. "three"

redis 127.0.0.1:6379>

在此处我们依次插入了 one,two,three,然后将标是 0 的值设置为 four,再将下标是-2 的值设置为 five。

2.5.5 lrem

从 key 对应 list 中删除 count 个和 value 相同的元素。count>0    时,按从头到尾的顺序删除,具体如下:

redis 127.0.0.1:6379> rpush mylist5 "hello" (integer) 1

redis 127.0.0.1:6379> rpush mylist5 "hello" (integer) 2

redis 127.0.0.1:6379> rpush mylist5 "foo" (integer) 3

redis 127.0.0.1:6379> rpush mylist5 "hello" (integer) 4

redis 127.0.0.1:6379> lrem mylist5 2 "hello"

(integer) 2

redis 127.0.0.1:6379> lrange mylist5 0 -1

  1. "foo"
  2. "hello"

redis 127.0.0.1:6379>

count<0    时,按从尾到头的顺序删除,具体如下:

redis 127.0.0.1:6379> rpush mylist6 "hello" (integer) 1

redis 127.0.0.1:6379> rpush mylist6 "hello" (integer) 2

redis 127.0.0.1:6379> rpush mylist6 "foo" (integer) 3

redis 127.0.0.1:6379> rpush mylist6 "hello" (integer) 4

redis 127.0.0.1:6379> lrem mylist6 -2 "hello"

(integer) 2

redis 127.0.0.1:6379> lrange mylist6 0 -1

  1. "hello"
  2. "foo"

redis 127.0.0.1:6379>

count=0 时,删除全部,具体如下:

redis 127.0.0.1:6379> rpush mylist7 "hello" (integer) 1

redis 127.0.0.1:6379> rpush mylist7 "hello" (integer) 2

redis 127.0.0.1:6379> rpush mylist7 "foo"

(integer) 3

redis 127.0.0.1:6379> rpush mylist7 "hello" (integer) 4

redis 127.0.0.1:6379> lrem mylist7 0 "hello"

(integer) 3

redis 127.0.0.1:6379> lrange mylist7 0 -1

1) "foo"

redis 127.0.0.1:6379>

2.4.6 ltrim

保留指定 key 的值范围内的数据

redis 127.0.0.1:6379> rpush mylist8 "one" (integer) 1

redis 127.0.0.1:6379> rpush mylist8 "two" (integer) 2

redis 127.0.0.1:6379> rpush mylist8 "three" (integer) 3

redis 127.0.0.1:6379> rpush mylist8 "four" (integer) 4

redis 127.0.0.1:6379> ltrim mylist8 1 -1

OK

redis 127.0.0.1:6379> lrange mylist8 0 -1

  1. "two"
  2. "three"
  3. "four"

redis 127.0.0.1:6379>

2.4.7 lpop

从 list 的头部删除元素,并返回删除元素

redis 127.0.0.1:6379> lrange mylist 0 -1

  1. "hello"
  2. "world"

redis 127.0.0.1:6379> lpop mylist

"hello"

redis 127.0.0.1:6379> lrange mylist 0 -1

1) "world"

redis 127.0.0.1:6379>

2.4.8 rpop

从 list 的尾部删除元素,并返回删除元素

redis 127.0.0.1:6379> lrange mylist2 0 -1

  1. "hello"
  2. "world"

redis 127.0.0.1:6379> rpop mylist2

"world"

redis 127.0.0.1:6379> lrange mylist2 0 -1

1) "hello"

redis 127.0.0.1:6379>

 

2.4.9 rpoplpush

从第一个 list 的尾部移除元素并添加到第二个 list 的头部,最后返回被移除的元素值,整个操作是原子的.如果第一个 list 是空或者不存在返回 nil

redis 127.0.0.1:6379> lrange mylist5 0 -1

  1. "three"
  2. "foo"
  3. "hello"

redis 127.0.0.1:6379> lrange mylist6 0 -1

  1. "hello"
  2. "foo"

redis 127.0.0.1:6379> rpoplpush mylist5 mylist6

"hello"

redis 127.0.0.1:6379> lrange mylist5 0 -1

  1. "three"
  2. "foo"

redis 127.0.0.1:6379> lrange mylist6 0 -1

  1. "hello"
  2. "hello"
  3. "foo"

redis 127.0.0.1:6379>

 

2.4.10 lindex

返回名称为 key 的 list 中 index 位置的元素

redis 127.0.0.1:6379> lrange mylist5 0 -1

  1. "three"
  2. "foo"

redis 127.0.0.1:6379> lindex mylist5 0

"three"

redis 127.0.0.1:6379> lindex mylist5 1

"foo"

redis 127.0.0.1:6379>

2.4.11 llen

返回 key 对应 list 的长度

redis 127.0.0.1:6379> llen mylist5

(integer) 2

redis 127.0.0.1:6379>

2.5 sets类型以及操作

set 是集合,和我们数学中的集合概念相似,对集合的操作有添加删除元素,有对多个集合求交并差等操作,操作中 key 理解为集合的名字。set 的是通过 hash table 实现的,所以添加、删除和查找的复杂度都是 O(1)。hash table 会随着添加或者删除自动的调整大小。需要注意的是调整 hash table 大小时候需要同步(获取写锁)会阻塞其他读写操作,可能不久后就会改用跳表(skip list)来实现,跳表已经在 sortedset 中使用了。关于 set 集合类型除了基本的添加删除操作,其他有用的操作还包含集合的取并集(union),交集(intersection),差集(difference)。通过这些操作可以很容易的实现   sns 中的好友推荐和 blog 的 tag 功能。下面详细介绍 set 相关命令:

2.5.1 sadd

向名称为 key 的 set 中添加元素

redis 127.0.0.1:6379> sadd myset "hello"

(integer) 1

redis 127.0.0.1:6379> sadd myset "world" (integer) 1

redis 127.0.0.1:6379> sadd myset "world"

(integer) 0

redis 127.0.0.1:6379> smembers myset

  1. "world"
  2. "hello"

redis 127.0.0.1:6379>

2.5.2 srem

删除名称为 key 的 set 中的元素 member

redis 127.0.0.1:6379> sadd myset2 "one" (integer) 1

redis 127.0.0.1:6379> sadd myset2 "two" (integer) 1

redis 127.0.0.1:6379> sadd myset2 "three" (integer) 1

redis 127.0.0.1:6379> srem myset2 "one"

(integer) 1

redis 127.0.0.1:6379> srem myset2 "four"

(integer) 0

redis 127.0.0.1:6379> smembers myset2

  1. "three"
  2. "two"

redis 127.0.0.1:6379>

 

 2.5.3 spop

随机返回并删除名称为 key 的 set 中一个元素

redis 127.0.0.1:6379> sadd myset3 "one" (integer) 1

redis 127.0.0.1:6379> sadd myset3 "two" (integer) 1

redis 127.0.0.1:6379> sadd myset3 "three" (integer) 1

redis 127.0.0.1:6379> spop myset3

"three"

redis 127.0.0.1:6379> smembers myset3

  1. "two"
  2. "one"

redis 127.0.0.1:6379>

本例中,我们向 myset3 中添加了三个元素后,再调用 spop 来随机删除一个元素,可以看到three 元素被删除了。

2.5.4 sdiff

返回所有给定 key 与第一个 key 的差集

redis 127.0.0.1:6379> smembers myset2

  1. "three"
  2. "two"

redis 127.0.0.1:6379> smembers myset3

  1. "two"
  2. "one"

redis 127.0.0.1:6379> sdiff myset2 myset3

1) "three"

redis 127.0.0.1:6379>

本例中,我们可以看到 myset2 中的元素与 myset3 中不同的只是 three,所以只有 three 被查出来了,而不是 three 和 one,因为 one 是 myset3 的元素。

 

我们也可以将 myset2 和 myset3 换个顺序来看一下结果:

redis 127.0.0.1:6379> sdiff myset3 myset2

1) "one"

redis 127.0.0.1:6379>

这个结果中只显示了,myset3 中的元素与 myset2 中不同的元素。

2.5.5 sdiffstore

返回所有给定 key 与第一个 key 的差集,并将结果存为另一个 key

redis 127.0.0.1:6379> smembers myset2
1) "three"
2) "two"
redis 127.0.0.1:6379> smembers myset3
1) "two"
2) "one"
redis 127.0.0.1:6379> sdiffstore myset4 myset2 myset3
(integer) 1
redis 127.0.0.1:6379> smembers myset4
1) "three"
redis 127.0.0.1:6379>

2.5.6 sinter

返回所有给定 key 的交集


redis 127.0.0.1:6379> smembers myset2
1) "three"
2) "two"
redis 127.0.0.1:6379> smembers myset3
1) "two"
2) "one"
redis 127.0.0.1:6379> sinter myset2 myset3
1) "two

redis 127.0.0.1:6379>

通过本例的结果可以看出, myset2 和 myset3 的交集 two 被查出来了

2.5.7 sinterstore

返回所有给定 key 的交集,并将结果存为另一个 key

redis 127.0.0.1:6379> smembers myset2
1) "three"
2) "two"
redis 127.0.0.1:6379> smembers myset3
1) "two"
2) "one"
redis 127.0.0.1:6379> sinterstore myset5 myset2 myset3
(integer) 1
redis 127.0.0.1:6379> smembers myset5
1) "two"
redis 127.0.0.1:6379>

通过本例的结果可以看出, myset2 和 myset3 的交集被保存到 myset5 中了

2.5.8 sunion

返回所有给定 key 的并集

redis 127.0.0.1:6379> smembers myset2
1) "three"
2) "two"
redis 127.0.0.1:6379> smembers myset3
1) "two"
2) "one"
redis 127.0.0.1:6379> sunion myset2 myset3
1) "three"
2) "one"
3) "two"
redis 127.0.0.1:6379>

通过本例的结果可以看出, myset2 和 myset3 的并集被查出来了

2.5.9 sunionstore

返回所有给定 key 的并集,并将结果存为另一个 key

redis 127.0.0.1:6379> smembers myset2
1) "three"
2) "two"
redis 127.0.0.1:6379> smembers myset3

1) "two"
2) "one"
redis 127.0.0.1:6379> sunionstore myset6 myset2 myset3
(integer) 3
redis 127.0.0.1:6379> smembers myset6
1) "three"
2) "one"
3) "two"
redis 127.0.0.1:6379>

通过本例的结果可以看出, myset2 和 myset3 的并集被保存到 myset6 中了

2.5.10 smove

从第一个 key 对应的 set 中移除 member 并添加到第二个对应 set 中

redis 127.0.0.1:6379> smembers myset2
1) "three"
2) "two"
redis 127.0.0.1:6379> smembers myset3
1) "two"
2) "one"
redis 127.0.0.1:6379> smove myset2 myset7 three
(integer) 1
redis 127.0.0.1:6379> smembers myset7
1) "three"
redis 127.0.0.1:6379>

通过本例可以看到,myset2 的 three 被移到 myset7 中了

2.5.11 scard

返回名称为 key 的 set 的元素个数

redis 127.0.0.1:6379> scard myset2
(integer) 1
redis 127.0.0.1:6379

通过本例可以看到,myset2 的成员数量为 1

2.5.12 sismemb

测试 member 是否是名称为 key 的 set 的元素

redis 127.0.0.1:6379> smembers myset2
1) "two"
redis 127.0.0.1:6379> sismember myset2 two
(integer) 1

redis 127.0.0.1:6379> sismember myset2 one
(integer) 0
redis 127.0.0.1:6379

通过本例可以看到,two 是 myset2 的成员,而 one 不是。

2.5.13 srandmemb

随机返回名称为 key 的 set 的一个元素,但是不删除元素

redis 127.0.0.1:6379> smembers myset3
1) "two"
2) "one"
redis 127.0.0.1:6379> srandmember myset3
"two"
redis 127.0.0.1:6379> srandmember myset3
"one"
redis 127.0.0.1:6379>

2.6 sorted sets 类型及操作

sorted set 是 set 的一个升级版本,它在 set 的基础上增加了一个顺序属性,这一属性在添加
修改元素的时候可以指定,每次指定后,zset 会自动重新按新的值调整顺序。可以理解为有
两列的 mysql 表,一列存 value,一列存顺序。操作中 key 理解为 zset 的名字。
和 set 一样 sorted set 也是 string 类型元素的集合,不同的是每个元素都会关联一个 double
类型的 score。sorted set 的实现是 skip list 和 hash table 的混合体。
当元素被添加到集合中时,一个元素到 score 的映射被添加到 hash table 中,所以给定一个
元素获取 score 的开销是 O(1),另一个 score 到元素的映射被添加到 skip list,并按照 score 排
序,所以就可以有序的获取集合中的元素。添加,删除操作开销都是 O(log(N))和 skip list 的
开销一致,redis 的 skip list 实现用的是双向链表,这样就可以逆序从尾部取元素。sorted set 最
经常的使用方式应该是作为索引来使用.我们可以把要排序的字段作为 score 存储,对象的 id
当元素存储。下面是 sorted set 相关命令

2.6.1 zadd

向名称为 key 的 zset 中添加元素 member,score 用于排序。如果该元素已经存在,则根据
score 更新该元素的顺序

redis 127.0.0.1:6379> zadd myzset 1 "one"
(integer) 1
redis 127.0.0.1:6379> zadd myzset 2 "two"
(integer) 1
redis 127.0.0.1:6379> zadd myzset 3 "two"

(integer) 0
redis 127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "3"
redis 127.0.0.1:6379>

本例中我们向 myzset 中添加了 one 和 two,并且 two 被设置了 2 次,那么将以最后一次的
设置为准,最后我们将所有元素都显示出来并显示出了元素的 score。

 

2.6.2 zrem

删除名称为 key 的 zset 中的元素 member

redis 127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "3"
redis 127.0.0.1:6379> zrem myzset two
(integer) 1
redis 127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "one"
2) "1"
redis 127.0.0.1:6379>

可以看到 two 被删除了

2.6.3 zincrby

如果在名称为 key 的 zset 中已经存在元素 member,则该元素的 score 增加 increment;否则
向集合中添加该元素,其 score 的值为 increment

redis 127.0.0.1:6379> zadd myzset2 1 "one"
(integer) 1
redis 127.0.0.1:6379> zadd myzset2 2 "two"
(integer) 1
redis 127.0.0.1:6379> zincrby myzset2 2 "one"
"3"
redis 127.0.0.1:6379> zrange myzset2 0 -1 withscores
1) "two"
2) "2"
3) "one"
4) "3"
redis 127.0.0.1:6379>

本例中将 one 的 score 从 1 增加了 2,增加到了 3

2.6.4 zrank

返回名称为 key 的 zset 中 member 元素的排名(按 score 从小到大排序)即下标

redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "five"
8) "5"
redis 127.0.0.1:6379> zrank myzset3 two
(integer) 1
redis 127.0.0.1:6379>

本例中将 two 的下标是 1,我这里取的是下标,而不是 score

2.6.5 zrevrank

返回名称为 key 的 zset 中 member 元素的排名(按 score 从大到小排序)即下标

redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "five"
8) "5"
redis 127.0.0.1:6379> zrevrank myzset3 two
(integer) 2
redis 127.0.0.1:6379>

按从大到小排序的话 two 是第三个元素,下标是 2

2.6.6 zrevrange

返回名称为 key 的 zset(按 score 从大到小排序)中的 index 从 start 到 end 的所有元素

redis 127.0.0.1:6379> zrevrange myzset3 0 -1 withscores
1) "five"
2) "5"
3) "three"
4) "3"

5) "two"
6) "2"
7) "one"
8) "1"
redis 127.0.0.1:6379>

首先按 score 从大到小排序,再取出全部元素

2.6.7 zrangebyscore

redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "five"
8) "5"
redis 127.0.0.1:6379> zrangebyscore myzset3 2 3 withscores
1) "two"
2) "2"
3) "three"
4) "3"
redis 127.0.0.1:6379>

本例中,返回了 score 在 2~3 区间的元素

2.6.8 zcount

返回集合中 score 在给定区间的数量

redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "five"
8) "5"
redis 127.0.0.1:6379> zcount myzset3 2 3
(integer) 2
redis 127.0.0.1:6379>

本例中,计算了 score 在 2~3 之间的元素数目

2.6.9 zcard

返回集合中元素个数

redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "five"
8) "5"
redis 127.0.0.1:6379> zcard myzset3
(integer) 4
redis 127.0.0.1:6379>

从本例看出 myzset3 这个集全的元素数量是 4

2.6.10 zscore

返回给定元素对应的 score

redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "five"
8) "5"
redis 127.0.0.1:6379> zscore myzset3 two
"2"
redis 127.0.0.1:6379>

此例中我们成功的将 two 的 score 取出来了

2.6.11 zremrangebyrank

删除集合中排名在给定区间的元素

redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"

5) "three"
6) "3"
7) "five"
8) "5"
redis 127.0.0.1:6379> zremrangebyrank myzset3 3 3
(integer) 1
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
redis 127.0.0.1:6379>

在本例中我们将 myzset3 中按从小到大排序结果的下标为 3 的元素删除了。

2.6.12 zremrangebyscore

删除集合中 score 在给定区间的元素

redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
redis 127.0.0.1:6379> zremrangebyscore myzset3 1 2
(integer) 2
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) "three"
2) "3"
redis 127.0.0.1:6379>

在本例中我们将 myzset3 中按从小到大排序结果的 score 在 1~2 之间的元素删除了。

这个世界,连区分对错都没有。

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/boss2967/article/details/82746775