Redis 入門 01 - 五種數(shù)據(jù)類型

1. 安裝 Redis


docker pull redis:3.0-alpine
docker images
docker run --restart=always -d -p 6379:6379 -v /root/redis/data:/home/renzheng/redis/data xxx --requirepass "password"
docker exec -it xxx sh

2. 熱身

2.1 使用 redis-cli,并驗(yàn)證密碼:

renzheng@qingdao:~$ docker exec -it 813 sh
/data # redis-cli
127.0.0.1:6379> auth bP623f@dhNfb
OK

選擇數(shù)據(jù)庫 (Redis 命令不區(qū)分大小寫)

127.0.0.1:6379> select 0
OK
127.0.0.1:6379> select 1
OK

2.2 獲得符合規(guī)則的 keys 列表

  • *:任意個(gè)字符
  • ?:一個(gè)或多個(gè)字符
  • a[a-c]:aa、ab、ac

keys * 會(huì)遍歷 Redis 中所有鍵,如果鍵的數(shù)量較多則會(huì)影響性能,生產(chǎn)環(huán)境不建議使用

127.0.0.1:6379[1]> incr foo
(integer) 1
127.0.0.1:6379[1]> incr fool
(integer) 1
127.0.0.1:6379[1]> keys fo* 
1) "foo"
2) "fool"

設(shè)值和取值:

127.0.0.1:6379[1]> set bar 1
OK
127.0.0.1:6379[1]> get bar
"1"

2.3 判斷一個(gè)鍵是否存在

存在返回整數(shù)類型 1,否則返回 0

127.0.0.1:6379[1]> exists bar
(integer) 1

2.4 刪除鍵

127.0.0.1:6379[1]> del bar
(integer) 1

Redis 中的 del 命令不支持批量刪除,但是我們可以憑借 Linux 的管道刪除多個(gè)鍵:

redis-cli keys "user*" | xargs redis-cli del

2.5 獲得鍵值的數(shù)據(jù)類型

type 命令用于獲取鍵值的數(shù)據(jù)類型,返回值可能是 string(字符串)、hash(散列)、list(列表)、set(集合類型)、zset(有序集合類型)。

127.0.0.1:6379[1]> set bar 1
OK
127.0.0.1:6379[1]> type bar
string
127.0.0.1:6379[1]> get bar
"1"

3. 字符串類型

字符串類型是 Redis 中最基本的數(shù)據(jù)類型,能夠存儲(chǔ)任何形式的字符串,包括二進(jìn)制數(shù)據(jù)。例如,可以存儲(chǔ)一個(gè)郵箱,JSON 序列化之后的對象,甚至是一張圖片。一個(gè)字符串類型鍵允許存儲(chǔ)的是數(shù)據(jù)最大容量是 512 MB。

3.1 命令

3.1.1 賦值和取值

SET key value
GET key

例如:

127.0.0.1:6379[1]> set greet "Hi!"
OK
127.0.0.1:6379[1]> get greet
"Hi!"

如果鍵不存在會(huì)返回空結(jié)果

127.0.0.1:6379[1]> get a
(nil)

3.1.2 遞增數(shù)字

INCR num

當(dāng)存儲(chǔ)的字符串是整數(shù)形式時(shí),Redis 提供了一個(gè) INCR 命令,可以讓當(dāng)前的鍵值遞增,并返回遞增后的值,如果鍵不存在會(huì)默認(rèn)賦值 0。例如:

127.0.0.1:6379[1]> incr foo
(integer) 1
127.0.0.1:6379[1]> incr foo
(integer) 2
127.0.0.1:6379[1]> type foo
string
127.0.0.1:6379[1]> get foo
"2"

如果鍵不是整數(shù),則出現(xiàn)如下錯(cuò)誤:

127.0.0.1:6379[1]> incr greet
(error) ERR value is not an integer or out of range

包括 INCR 在內(nèi)的所有 Redis 命令均為原子操作,不會(huì)出現(xiàn)并發(fā)沖突問題。

3.2 實(shí)踐

3.2.1 文章訪問量統(tǒng)計(jì)

每次訪問文章使用 INCR 命令使響應(yīng)的鍵值遞增。

鍵一般使用 object:id:property 的形式,例如:post:1:page.view

3.2.2 生成自增 id

每新增一個(gè)對象都使用 INCR 命令。

INCR user:count

3.2.3 存儲(chǔ)文章數(shù)據(jù)

對象序列化(JSON,MessagePack 等方式)。以存儲(chǔ) id 為 1的 文章為例:

set post:1:data str

3.3 其他命令

3.3.1 增加指定的整數(shù)

INCRBY 命令可以通過 increment 參數(shù)指定一次增加的數(shù)值

INCRBY key increment
127.0.0.1:6379[1]> set foo 100
OK
127.0.0.1:6379[1]> incrby foo 100
(integer) 200
127.0.0.1:6379[1]> get foo
"200"

3.3.2 減少指定的整數(shù)

DECR 命令與 INCR 命令用法相同,區(qū)別是讓數(shù)值減少。與 INCRBY 命令的相似的便是 DECRBY 命令。

3.3.3 增加指定的浮點(diǎn)數(shù)

INCRBYFLOAT 命令類似 INCR 命令,差別是可以增加一個(gè)雙精度浮點(diǎn)數(shù)。

INCRBYFLOAT key increment

例如:

127.0.0.1:6379[1]> set foo 1.000001
OK
127.0.0.1:6379[1]> incrbyfloat foo 0.000000003
"1.000001003"

3.3.4 向尾部追加值

APPEND 命令用來向鍵值末尾追加值。如果鍵不存在將該鍵的值設(shè)置為 value。

APPEND key value

例如:

127.0.0.1:6379[1]> set foo "Hello"
OK
127.0.0.1:6379[1]> append foo ", world!"
(integer) 13
127.0.0.1:6379[1]> get foo
"Hello, world!"

3.3.5 獲取字符串長度

STRLEN key

例如:

127.0.0.1:6379[1]> strlen foo
(integer) 13

3.3.6 同時(shí)獲得/設(shè)置多個(gè)鍵值

MSET/MGET 命令與 GET/SET 命令相似,只不過 MSET/MGET 可以設(shè)置/獲取多個(gè)鍵值。

MGET key [key ...]
MSET key value [key value ...]

例如:

127.0.0.1:6379[1]> mset foo 1 bar 2
OK
127.0.0.1:6379[1]> mget foo bar
1) "1"
2) "2"

3.3.7 位操作

GETBIT key offset (offset 從 0 開始)
SETBIT key offset value
BITCOUNT key
BITOP operation destkey key [key ...]

將 foo 設(shè)置為 "abc"(01100001 01100010 ..

127.0.0.1:6379[1]> set foo abc
OK

獲取第 1、6 個(gè) bit

127.0.0.1:6379[1]> getbit foo 1
(integer) 1
127.0.0.1:6379[1]> getbit foo 6
(integer) 0

如果偏移量超出鍵值實(shí)際長度,則默認(rèn)為 0

127.0.0.1:6379[1]> getbit foo 30
(integer) 0

BITCOUNT 命令可以獲得字符串類型鍵中值為 1 的二進(jìn)制位個(gè)數(shù),例如:

127.0.0.1:6379[1]> bitcount foo
(integer) 10

可以通過參數(shù)限制統(tǒng)計(jì)的字節(jié)范圍,例如只統(tǒng)計(jì)前兩個(gè)字節(jié):

127.0.0.1:6379[1]> bitcount foo 0 1
(integer) 6

SETBIT 命令可以設(shè)置字符串類型鍵指定位置的二進(jìn)制位的值,返回值是該位置的舊值:

127.0.0.1:6379[1]> setbit foo 1 0
(integer) 1
127.0.0.1:6379[1]> get foo
"!bc"

如果設(shè)置一個(gè)不存在的鍵的指定二進(jìn)制位的值,會(huì)自動(dòng)將其前面的位賦值為 0:

127.0.0.1:6379[1]> setbit test 10 0
(integer) 0
127.0.0.1:6379[1]> get test
"\x00\x00"

如果指定的二進(jìn)制位超過了鍵值的實(shí)際長度,那么會(huì)自動(dòng)將中間的位全部設(shè)置為 0

127.0.0.1:6379[1]> setbit foo 31 0
(integer) 0
127.0.0.1:6379[1]> get foo
"!bc\x00"

BITOP 命令可以對多個(gè)字符串類型鍵進(jìn)行位運(yùn)算,并將結(jié)果存在 destkey 指定的鍵中。支持的運(yùn)算操作有 ANDOR、XORNOT。

127.0.0.1:6379[1]> set foo bar
OK
127.0.0.1:6379[1]> set foo aaa
OK
127.0.0.1:6379[1]> set bar bbb
OK
127.0.0.1:6379[1]> bitop or res foo bar
(integer) 3
127.0.0.1:6379[1]> get res
"ccc"

4. 散列(hash)類型

散列類型(hash)的鍵值也是一種字典結(jié)構(gòu),其存出了字段和字段值的映射,但是字段值只能是字符串,不支持其他數(shù)據(jù)類型。一個(gè)散列類型鍵至多包含 2^32 -1 個(gè)字段。

散列類型適合存儲(chǔ)對象,以 object:id 構(gòu)成鍵名,使用字段表示對象的屬性,自字段值則存儲(chǔ)屬性值,例如:

[圖片上傳失敗...(image-cf3390-1653622114110)]

散列類型不像關(guān)系型數(shù)據(jù)庫那樣要求所有的記錄都有同樣的屬性,而存在無法為單獨(dú)的某條記錄增加屬性的問題。Redis 完全可以自由地為任何鍵增減字段而不影響其他鍵。

4.1 常用命令

4.1.1 取值與賦值

HSET key field value
HGET key field
HMSET key field value [field value ...]]
HMGET key field [field ...]
HGETALL key

例如:

127.0.0.1:6379[1]> hset car color red (不存在該字段則建立該字段,返回 1;存在則更新,返回 0)
(integer) 1
127.0.0.1:6379[1]> hset car name "BMW"
(integer) 1
127.0.0.1:6379[1]> hset car price "500000"
(integer) 1
127.0.0.1:6379[1]> hmget car color name price
1) "red"
2) "BMW"
3) "500000"
127.0.0.1:6379[1]> hgetall car
1) "color"
2) "red"
3) "name"
4) "BMW"
5) "price"
6) "500000"
127.0.0.1:6379[1]> type car
hash

4.1.2 判斷字段是否存在

HEXISTS key field

例如:

127.0.0.1:6379[1]> hexists car color
(integer) 1 (存在返回 1,不存在返回 0)

4.1.3 當(dāng)字段不存在時(shí)賦值

HSETNX key field value

HSETINX 命令與 HSET 命令相似,只不過 HSETNX 只有字段不存在時(shí)才賦值,字段如果存在則不執(zhí)行任何操作。

127.0.0.1:6379[1]> hsetnx person age 1
(integer) 0 // 存在返回 0
127.0.0.1:6379[1]> hget person age
"20"
127.0.0.1:6379[1]> hsetnx person height 165
(integer) 1 // 字段不存在,設(shè)值,且返回 1

4.1.4 增加數(shù)字

HINCRBY key field increment

HINCRBY 命令與 INCRBY 命令相似,如果字段不存在。Hash 類型沒有類似 INCR 的命令,不過可以通過執(zhí)行 HINCRBY key field 1 來實(shí)現(xiàn)。如果鍵或者字段不存在,那么將自動(dòng)創(chuàng)建鍵和字段,并賦值為 increment。

例:

127.0.0.1:6379[1]> hincrby car price 1
(integer) 500001
127.0.0.1:6379[1]> hincrby person age 20
(integer) 20
127.0.0.1:6379[1]> hgetall person
1) "age"
2) "20"

4.1.5 刪除字段

hdel key field

例:

127.0.0.1:6379[1]> hset person name "Renzheng"
(integer) 1
127.0.0.1:6379[1]> hgetall person
1) "age"
2) "20"
3) "name"
4) "Renzheng"
127.0.0.1:6379[1]> hdel person name
(integer) 1
127.0.0.1:6379[1]> hgetall person
1) "age"
2) "20"

4.2 實(shí)踐

4.2.1 存儲(chǔ)文章數(shù)據(jù)

[圖片上傳失敗...(image-43c2a3-1653622114110)]

4.2.2 存儲(chǔ)文章縮略名

使用一個(gè)的 slug.to.id hash 類型鍵用于存儲(chǔ)文章縮略名和文章 ID 的對應(yīng)關(guān)系。

如果需要發(fā)布文章,偽代碼如下:

// 獲取文章 ID
$postId = INCR posts:count
// 判斷文章縮略名 slug 是否可用,如果不可用則賦值
$isSlugAvailable = HSETNX slug.to.id $slug $postId

// 縮略名存在
if $isSlugAvailable = 0
    exit

HMSET post:$postId title $title content $content slug $slug

4.3 其他命令

4.3.1 只獲取字段名或字段值

127.0.0.1:6379[1]> hkeys car
1) "color"
2) "name"
3) "price"
127.0.0.1:6379[1]> hvals car
1) "red"
2) "BMW"
3) "500001"

4.3.2 獲得字段數(shù)量

127.0.0.1:6379[1]> hlen car
(integer) 3

5. 列表(list)類型

List 類型可以存儲(chǔ)一個(gè)有序的字符串列表,常用的操作是向列表兩端添加元素,或者獲得列表的某一個(gè)片段。list 類型內(nèi)部由雙向鏈表實(shí)現(xiàn),所以向列表兩端添加元素的時(shí)間復(fù)雜度為 O(1),獲取越接近兩端的元素越快,代價(jià)是通過索引訪問元素比較慢。

場景:新鮮事(插入最新,獲取最新)、日志。

借助 list 類型,Redis 還可以作為隊(duì)列使用。

一個(gè) list 類型鍵最多容納 2^32 - 1 個(gè)元素。

5.1 常用命令

5.1.1 向列表兩端添加元素

LPUSH key value [value ...]
RPUSH key value [value ...]

LPUSH 命令用來向列表左邊添加元素,返回值為添加元素后列表的長度。

例如:

127.0.0.1:6379[1]> lpush nums 1
(integer) 1
127.0.0.1:6379[1]> lpush nums 2 3
(integer) 3

按照以上命令,nums 中元素變化如下:

[]
[1]
[3, 2, 1]

5.1.2 從列表兩端彈出元素

LPOP key
RPOP key

LPOP 命令可以從列表左邊彈出一個(gè)元素。該命令執(zhí)行兩個(gè)操作:

  1. 將列表左邊的元素從列表中移除
  2. 返回被移除的元素

例如:

127.0.0.1:6379[1]> lpop nums
"3"

5.1.3 獲取列表中元素的個(gè)數(shù)

LLEN key

如果 key 不存在,LLEN 命令返回 0。例如:

127.0.0.1:6379[1]> llen nums
(integer) 2
127.0.0.1:6379[1]> llen foo // foo 不存在
(integer) 0

LLEN 命令的功能類似于關(guān)系型數(shù)據(jù)庫中的 select count(*) from table_name,但是 LLEN 的時(shí)間復(fù)雜度為 O(1),使用時(shí)會(huì)直接讀取現(xiàn)成的值,并不需要遍歷一遍獲得數(shù)據(jù)。

5.1.4 獲得列表片段

LRANGE key start stop

LRANGE 可以獲得列表中的一個(gè)片段,返回索引從 startstop 之間的元素(索引從 0 開始,包括 stop 元素)。

例如:

127.0.0.1:6379[1]> lrange nums 0 1
1) "2"
2) "1"

LRANGE 命令也支持負(fù)索引,表示從右邊開始計(jì)算,如 -1 表示從最右邊第一個(gè)元素開始,-2 表示最右邊第二個(gè)元素,依此類推。

127.0.0.1:6379[1]> lrange nums -2 -1
1) "2"
2) "1"

如果 stop 大于實(shí)際的索引范圍,則會(huì)返回到列表中最右邊的元素。

5.1.5 刪除列表中指定的值

LREM key count value

LREM 命令將刪除前 count 個(gè)值為 value 的元素,返回實(shí)際刪除的元素。

例如:

127.0.0.1:6379[1]> lpush nums 1 0 1 0 1 0 1 0 1 0
(integer) 10
127.0.0.1:6379[1]> lrange nums 0 -1 
 1) "0"
 2) "1"
 3) "0"
 4) "1"
 5) "0"
 6) "1"
 7) "0"
 8) "1"
 9) "0"
10) "1"
127.0.0.1:6379[1]> lrem nums 3 1
(integer) 3
127.0.0.1:6379[1]> lrange nums 0 -1
1) "0"
2) "0"
3) "0"
4) "0"
5) "1"
6) "0"
7) "1"

根據(jù) count 值的不同,LREM 命令的執(zhí)行方式會(huì)略有差異:

  • count > 0 時(shí),LREM 命令會(huì)從左邊刪除前 count 個(gè)值為 value 的元素;

  • count < 0 時(shí),LREM 命令會(huì)刪除從右邊開始刪除前 |count| 個(gè)值為 value 的元素;

  • count = 0 時(shí),LREM 命令將刪除所有值為 value 的元素。

5.2 實(shí)踐

5.2.1 存儲(chǔ)文章 ID 列表

使用鍵 posts:list 記錄文章 ID 列表。當(dāng)發(fā)布新文章時(shí),使用 LPUSH 命令把文章的 ID 加入至這個(gè)列表中,刪除文章時(shí)將列表中的文章 ID 刪除??梢允褂?LRANGE 命令實(shí)現(xiàn)文章分頁列表,偽代碼如下:

$postPerPage = 10
$start = ($currentPage - 1) * $postsPerPage
$end = $currentPage * $postsPerPage - 1
$postIds = LRANGE posts:list $start $end

# 循環(huán)獲取文章信息
for $id in $postIds
    print HGET post:$id title

5.2.2 存儲(chǔ)文章評論

將文章評論序列化之后,使用字符串的形式將評論存入形如 posts:id:comments 的列表中。

偽代碼如下:

$serializedComment = serialize($author, $email, $time, $content)
LPUSH post:1:comments $serializedComment

讀取時(shí),依然使用 LRANGE 命令。

5.3 其他命令

5.3.1 獲得/設(shè)置指定索引的元素值

LINDEX key index
LSET KEY index value

LINDEX 用來返回指定索引的元素,索引從 0 開始。

例如:

127.0.0.1:6379[1]> lrange nums 0 -1
 1) "0"
 2) "9"
 3) "8"
 4) "7"
 5) "6"
 6) "5"
 7) "4"
 8) "3"
 9) "2"
10) "1"
127.0.0.1:6379[1]> lindex nums 0
"0"
127.0.0.1:6379[1]> lindex nums 2
"8"

LSET 命令將索引為 index 的元素設(shè)置為 value,例如:

127.0.0.1:6379[1]> lset nums 0 99999
OK
127.0.0.1:6379[1]> lrange nums 0 -1
 1) "99999"
 2) "9"
 3) "8"
 4) "7"
 5) "6"
 6) "5"
 7) "4"
 8) "3"
 9) "2"
10) "1"

5.3.2 只保留列表指定片段

LTRIM key start end

LTRIM 命令可以刪除指定索引范圍之外的所有元素,其指定的列表范圍的方法和 LRANGE 命令相同。

例如:

127.0.0.1:6379[1]> lrange nums 0 -1
 1) "99999"
 2) "9"
 3) "8"
 4) "7"
 5) "6"
 6) "5"
 7) "4"
 8) "3"
 9) "2"
10) "1"
127.0.0.1:6379[1]> ltrim nums 1 -1
OK
127.0.0.1:6379[1]> lrange nums 0 -1
1) "9"
2) "8"
3) "7"
4) "6"
5) "5"
6) "4"
7) "3"
8) "2"
9) "1"

5.3.3 向列表中插入元素

LINSERT key BEFORE|AFTER pivot value

LINSERT 命令在列表中從左到右查找值為 pivot 的元素,然后根據(jù)第二個(gè)參數(shù)是 BEFORE 還是 AFTER 決定將 value 插入到該元素的前面還是后面。LINSERT 命令的返回值為插入后列表元素的個(gè)數(shù)。

例如:

127.0.0.1:6379[1]> lrange nums 0 -1
 1) "1"
 2) "9"
 3) "8"
 4) "7"
 5) "6"
 6) "5"
 7) "4"
 8) "3"
 9) "2"
10) "1"
127.0.0.1:6379[1]> linsert nums before 1 0
(integer) 11
127.0.0.1:6379[1]> lrange nums 0 -1
 1) "0"
 2) "1"
 3) "9"
 4) "8"
 5) "7"
 6) "6"
 7) "5"
 8) "4"
 9) "3"
10) "2"
11) "1"

5.3.4 將元素從一個(gè)列表轉(zhuǎn)移至另一個(gè)列表

RPOPLPUSH src des

RPOPLPUSH 命令會(huì)先從 src 列表的右邊彈出一個(gè)元素,然后將其加入至 des 列表的左邊,并返回這個(gè)元素的值。整個(gè)過程是原子的。

6. 集合(set)類型

在集合中每個(gè)元素都是不同的,而且沒有順序。一個(gè) set 類型的鍵可以至多存儲(chǔ) 2^32 - 1 個(gè)字符串。

[圖片上傳失敗...(image-e0c4ba-1653622114110)]

集合類型在 Redis 內(nèi)部是使用值為空的 Hash Table 實(shí)現(xiàn)的。

6.1 常用命令

6.1.1 增加/刪除元素

SADD key member [member ...]
SREM key [member] [member ...]

SADD 命令用于向集合中添加一個(gè)元素或多個(gè)元素,如果鍵不存在則自動(dòng)創(chuàng)建,元素已存在則忽略。返回值為成功加入元素的數(shù)量。

例如:

127.0.0.1:6379[1]> sadd foo a
(integer) 1
127.0.0.1:6379[1]> sadd foo a b c
(integer) 2

SREM 命令用于從集合中刪除一個(gè)或者多個(gè)元素,返回成功刪除的個(gè)數(shù)。

例如:

127.0.0.1:6379[1]> srem foo a d
(integer) 1

6.1.2 獲得集合中所有元素

SMEMBERS key

SMEMBERS 命令從集合中返回所有元素。例如:

127.0.0.1:6379[1]> del foo
(integer) 1
127.0.0.1:6379[1]> sadd foo a b c
(integer) 3
127.0.0.1:6379[1]> smembers foo
1) "c"
2) "b"
3) "a"

6.1.3 判斷元素是否存在于集合中

SISMEMBER key member

時(shí)間復(fù)雜度為 O(1),SISMEMBER 當(dāng)值存在時(shí)返回 1,當(dāng)值不存在或者鍵不存在時(shí)返回 0。例如:

127.0.0.1:6379[1]> sismember foo a
(integer) 1
127.0.0.1:6379[1]> sismember foo d
(integer) 0

6.1.4 集合運(yùn)算

SDIFF key [key ...]
SINTER key [key ...]
SUNION key [key ...]
  • SDIFF 用來對集合之間執(zhí)行差集運(yùn)算。

    127.0.0.1:6379[1]> sadd aset a b c
    (integer) 3
    127.0.0.1:6379[1]> sadd bset b c d
    (integer) 3
    127.0.0.1:6379[1]> sdiff aset bset
    1) "a"
    127.0.0.1:6379[1]> smembers aset
    1) "c"
    2) "b"
    3) "a"
    
  • SINTER 用來對多個(gè)集合執(zhí)行交集運(yùn)算。

    127.0.0.1:6379[1]> sinter aset bset
    1) "c"
    2) "b"
    
  • SUNION 用來對多個(gè)集合執(zhí)行并集運(yùn)算。

    127.0.0.1:6379[1]> sunion aset bset
    1) "c"
    2) "b"
    3) "d"
    4) "a"
    

6.2 實(shí)踐

6.2.1 存儲(chǔ)文章標(biāo)簽

一篇文章的各個(gè)標(biāo)簽均是不同的,而且展示時(shí)對這些標(biāo)簽的順序沒有要求,可以使用 set 類型鍵存儲(chǔ)文章標(biāo)簽。對每篇文章使用形如 posts:id:tags 的鍵存儲(chǔ)該篇文章的標(biāo)簽。

偽代碼如下:

SADD post:1:tags Java Spring MyBatis
SREM post:1:tags MyBatis

// 顯示所有標(biāo)簽
$tags = SMEMBERS post:1:tags

6.2.2 通過標(biāo)簽查詢文章

使用形如 tag:標(biāo)簽:posts 的 set 類型鍵存儲(chǔ)每個(gè)標(biāo)簽對應(yīng)標(biāo)簽。

6.3 其他命令

6.3.1 獲取集合中元素的個(gè)數(shù)

SCARD key

SCARD 命令用于獲取集合中元素的個(gè)數(shù),例如:

127.0.0.1:6379[1]> scard aset
(integer) 3

6.3.2 進(jìn)行集合運(yùn)算并將結(jié)果存儲(chǔ)

SDIFFSTORE des key [key ...]
SINTERSTORE des key [key ...]
SUNIONSTORE des key [key ...]

不直接返回運(yùn)算結(jié)果,而將結(jié)果存儲(chǔ)在 des 鍵中。

127.0.0.1:6379[1]> sdiffstore cset aset bset
(integer) 1
127.0.0.1:6379[1]> smembers cset
1) "a"

6.3.3 隨機(jī)獲取集合中的元素

SRANDMEMBER key [count]

SRANDMEMBER 命令用于隨機(jī)從集合中獲取一個(gè)元素,例如:

127.0.0.1:6379[1]> srandmember aset
"b"

也可以傳遞一個(gè) count 參數(shù)一次獲得多個(gè)元素,而根據(jù) count 參數(shù)的正負(fù)不同返回結(jié)果略有差異:

  • 當(dāng) count 為正數(shù)時(shí),SRANDMEMBER 命令將從集合中隨機(jī)獲得 count 個(gè)不重復(fù)的元素;
  • 當(dāng) count 為負(fù)數(shù)時(shí),SRANDMEMBER 命令將從集合中隨機(jī)獲得可能相同的 |count| 個(gè)元素。

6.3.4 從集合中彈出一個(gè)元素

SPOP key

由于集合是無序的,因此 SPOP 命令會(huì)從集合中隨機(jī)選擇一個(gè)元素彈出。例如:

127.0.0.1:6379[1]> spop aset
"a"
127.0.0.1:6379[1]> smembers aset
1) "c"
2) "b"

7. 有序集合

有序集合(sorted set) 類型在 set 類型的基礎(chǔ)上為集合中的每個(gè)元素都關(guān)聯(lián)了一個(gè)分?jǐn)?shù),這使得我們不僅可以完成插入、刪除、判斷是否存在等 set 類型支持的操作,還能進(jìn)行獲得分?jǐn)?shù)最高(最低)的前 N 個(gè)元素、獲得指定分?jǐn)?shù)范圍內(nèi)的元素等與分?jǐn)?shù)相關(guān)的操作。

雖然集合中每個(gè)元素都不相同,但是分?jǐn)?shù)可以相同。

7.1 命令

7.1.1 增加元素

ZADD key score member [score member]

ZADD 命令用于向 sorted set 中添加一個(gè)或多個(gè)元素及他們的分?jǐn)?shù),如果該元素已經(jīng)存在,那么則會(huì)用新的分?jǐn)?shù)替代舊的分?jǐn)?shù)。ZADD 命令的返回值為新加入集合中的元素個(gè)數(shù)。例如:

127.0.0.1:6379[1]> zadd scoreboard 98 Tom 87 Mike 94 Mary
(integer) 3
127.0.0.1:6379[1]> zadd scoreboard 86.5 Mike
(integer) 0
127.0.0.1:6379[1]> zadd scoreboard +inf Mike // 設(shè)置分?jǐn)?shù)為正無窮
(integer) 0
127.0.0.1:6379[1]> zadd scoreboard -inf Mike // 設(shè)置分?jǐn)?shù)為負(fù)無窮
(integer) 0

7.1.2 獲得元素的分?jǐn)?shù)

ZSCORE key member

例如:

127.0.0.1:6379[1]> zscore scoreboard Mike
"86.5"

7.1.3 獲得在某個(gè)排名范圍內(nèi)的元素列表

ZRANGE key start stop [withscores]
ZREVRANGE key start stop [withscores]

ZRANGE 命令會(huì)按照元素的分?jǐn)?shù)從小到大排序返回索引從 startstop 之間的所有元素(包括兩端),索引方式與 LRANGE 命令相同。ZREVRANGE 命令按照分?jǐn)?shù)從大到小排序。

127.0.0.1:6379[1]> zrange scoreboard 0 2
1) "Mike"
2) "Mary"
3) "Tom"
127.0.0.1:6379[1]> zrange scoreboard 0 2 withscores
1) "Mike"
2) "86.5"
3) "Mary"
4) "94"
5) "Tom"
6) "98"
127.0.0.1:6379[1]> zrevrange scoreboard 0 2 withscores
1) "Tom"
2) "98"
3) "Mary"
4) "94"
5) "Mike"
6) "86.5"

如果兩個(gè)元素的分?jǐn)?shù)相同,則按照字典順序排序。

7.1.4 獲取指定分?jǐn)?shù)范圍內(nèi)的元素

ZRANGEBYSCORE key min max [withscore] [limit offset count]

ZRANGEBYSCORE 命令按照元素分?jǐn)?shù)從小到大的順序返回分?jǐn)?shù)在 minmax 之間的元素,例如:

127.0.0.1:6379[1]> zrangebyscore scoreboard 80 90
1) "Mike"

如果希望分?jǐn)?shù)不包括端點(diǎn)值,則可以在分?jǐn)?shù)前加上 (,例如:

127.0.0.1:6379[1]> zrangebyscore scoreboard 80 86.5
(empty list or set)

minmax 還支持無窮大,類似于 ZADD 命令,-inf+inf 分別表示負(fù)無窮和正無窮。例如:

127.0.0.1:6379[1]> zrangebyscore scoreboard (80 +inf withscores
1) "Mike"
2) "88.5"
3) "Mary"
4) "94"
5) "Tom"
6) "98"

limit offset count 表示在獲得列表的基礎(chǔ)上,向后偏移 offset 個(gè)元素,并只獲取前 count 個(gè)元素。例如:

// 獲取高于 60 分并從第 2 個(gè)人開始的 3 個(gè)人
127.0.0.1:6379[1]> zrangebyscore scoreboard (60 +inf withscores limit 1 3
1) "Mary"
2) "94"
3) "Tom"
4) "98"

ZREVRANGEBYSCORE 命令命令不僅按照元素分?jǐn)?shù)從大到小排序,而且該命令的 minmax 參數(shù)順序和 ZRANGEBYSCORE 命令是相反的。

7.1.5 增加某個(gè)元素的分?jǐn)?shù)

ZINCRBY key increment member

ZINCRBY 命令可以增加某個(gè)元素的分?jǐn)?shù),返回值為更改之后的分?jǐn)?shù)。例如:

127.0.0.1:6379[1]> zincrby scoreboard 2 Mike
"88.5"
127.0.0.1:6379[1]> zrange scoreboard 0 -1 withscores
1) "Mike"
2) "88.5"
3) "Mary"
4) "94"
5) "Tom"
6) "98"

7.2 實(shí)踐

7.2.1 實(shí)現(xiàn)文章按照訪問量排序

使用鍵名 posts:page.view 的鍵記錄每篇文章的 ID 和訪問量,每次訪客訪問一篇文章,則通過 ZINCRBY posts:page.view 1 postId 更新訪問量。偽代碼如下:

$postsPerpage = 10
$start = $(currentPage - 1) * $postsPerPage
$end = $currentPage * $postsPerPage - 1;
$postIds = ZREVRANGE posts:page.view $start $end

foreach $id in $postIds
    $title = HGET post:$id title

7.2.2 改進(jìn)按照時(shí)間排序

同樣采用有序集合,記錄文章 ID 和 Unix 時(shí)間

7.3 其他命令

7.3.1 獲得集合中元素的數(shù)量

ZCARD key

例如:

127.0.0.1:6379[1]> zcard scoreboard
(integer) 3

7.3.2 獲得指定分?jǐn)?shù)范圍內(nèi)元素個(gè)數(shù)

ZCOUNT key min max

例如:

127.0.0.1:6379[1]> zcount scoreboard 80 90
(integer) 1

7.3.3 刪除一個(gè)或多個(gè)元素

ZREM key member

ZREM 返回值是成功刪除元素的數(shù)量

127.0.0.1:6379[1]> zrem scoreboard Mike
(integer) 1
127.0.0.1:6379[1]> zrange scoreboard 0 -1
(empty list or set)

7.3.4 按照排名范圍刪除元素

ZREMRANGEBYRANK key start stop

ZREMRANGEBYRANK 命令按照元素從?。ㄗ钚?0)到大排序刪除排名在指定范圍內(nèi)的所有元素,并返回刪除元素的數(shù)量。例如:

127.0.0.1:6379[1]> zremrangebyrank scoreboard 1 3
(integer) 2
127.0.0.1:6379[1]> zrange scoreboard 0 -1
1) "Mike"

7.3.5 按照分?jǐn)?shù)范圍刪除元素

ZREMRANGEBYSCORE key min max

ZREMRANGEBYSOCRE 會(huì)刪除指定分?jǐn)?shù)范圍內(nèi)所有的元素,參數(shù) minmax 的特性和 ZRANGEBYSCORE 命令中的一樣。返回值是刪除元素的數(shù)量。

7.3.6 獲得元素的排名

ZRANK key member
ZREVRANK key member

ZRANK 命令會(huì)按照元素分?jǐn)?shù)從小到大的順序獲得指定的元素排名,從0 開始。而 ZREVRANK 命令則相反,分?jǐn)?shù)最大的元素排名為 0。

7.3.6 計(jì)算有序集合的交集

ZINTERSTORE des numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]

ZINTERSTORE 命令用來計(jì)算多個(gè)有序集合的交集,并將結(jié)果存儲(chǔ)在 des 鍵中(同樣以有序集合類型存儲(chǔ)),返回值為 des 鍵中的元素個(gè)數(shù)。

des 鍵中元素的分?jǐn)?shù)由 AGGREGATE 參數(shù)決定:

  • 當(dāng) AGGREGATE 參數(shù)是 SUM (默認(rèn))時(shí),des 鍵中的元素分?jǐn)?shù)是每個(gè)參與計(jì)算集合中該元素分?jǐn)?shù)的和;
  • 當(dāng) AGGREGATE 參數(shù)是 MIN (默認(rèn))時(shí),des 鍵中的元素分?jǐn)?shù)是每個(gè)參與計(jì)算集合中該元素分?jǐn)?shù)的最小值;
  • 當(dāng) AGGREGATE 參數(shù)是 MAX (默認(rèn))時(shí),des` 鍵中的元素分?jǐn)?shù)是每個(gè)參與計(jì)算集合中該元素分?jǐn)?shù)的最大值;

ZINTERSTORE 命令還能通過 WEIGHTS 參數(shù)設(shè)置每個(gè)集合的權(quán)重,每個(gè)集合在參與計(jì)算時(shí)元素的分?jǐn)?shù)會(huì)被乘上該集合的權(quán)重。

另外還有一個(gè)命令 ZUNIONSTORE 計(jì)算集合并集,用法與 ZINTERSTORE 命令相同。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容