Redis數據模型

Redis數據模型

  • redis支持數據模型非常豐富

鍵Key

  • Redis key需要一個二進制值,可以用任何二進制序列作爲key值,可以是簡單字符串,也可以是個JPEG文件的二精製序列。空字符串也有效率key值

  • key取值原則

    1. 鍵值不需要太長,消耗內存,而且查找這類鍵值的計算成本較高
    2. 鍵值不宜過短,可讀性較差
    3. 習慣上key採用user:123:password形式,表示用戶id爲123的用戶的密碼

字符串

  • 字符串是一種基本簡單的Redis值類型。說是字符串,其實可以是任意可以序列化的數據。
  • 一個字符串類型的值最多能存儲512M字節的內容。

python中的redis編程

  • 安裝redis庫pip install redis
import redis

db = redis.Redis("192.168.61.109") #默認本地6379的0號庫

print(db.keys('*')) #查看所有匹配keys

db.set("xdd",0b01100010) #0x62
print(db.get("xdd"))

db.set(0b11,0x63)
print(db.get(0b11))
print(db.get(3))
print(db.get("3"))

print("- "*30)
print(db.keys('*')) #查看所有匹配keys

注意:上列中0x62實際上發生了類型變化,因爲返回的bytes類型98,實際上對應的ASCII的98,已經是2字節了。數值會轉換成10進制64位有符號數後,再轉成字符串,存入redis中。

查看幫助

  • 使用redis-cli可以進入redis命令行界面
> Help 查看幫助
> Help <tab> 使用tab建切換幫助
> Help set 查看set命令幫助
> Help @string 查看命令組幫助

在這裏插入圖片描述

字符串設置

  • 語法:SET key value [Ex seconds][PX milliseconds] [NX|XX]設置字符串值(設置單個鍵值)
    1. EX設置過期時間,秒,等同於SETEX key seconds value
    2. PX設置過期時間,毫秒,等同於PSETEX key millieconds value
    3. NX鍵不存在,才能設置,等同於SETNX key value
    4. XX鍵存在時,才能設置
  • 設置多個鍵值MSET key value [key value ...]
    1. 設置多個鍵值字符串,key存在則覆蓋,key不存在則增加。原子操作
  • MSETNX key value [key value ...]可以不存在則設置,key存在則失敗。nx指代不存在。也是原子操作命令。
127.0.0.1:6379> set s1 abc
OK
127.0.0.1:6379> get s1
"abc"
127.0.0.1:6379> mset s2 a s3 b s4 c
OK
127.0.0.1:6379> keys *
1) "xdd"
2) "3"
3) "s1"
4) "s2"
5) "s3"
6) "s4"
127.0.0.1:6379> msetnx s1 s
(integer) 0
127.0.0.1:6379> get s1
"abc"
127.0.0.1:6379>

過期操作和生存時間

  • Redis中可以給每個Key設置一個生存時間(秒或毫秒),當達到這個時長後,這些鍵值將會被自動刪除

  • 設置多少秒或者毫秒後過期

    1. EXPIRE key seconds設置key多少秒後過期
    2. PEXPIRE key milliseconds設置key多少毫秒後過期
  • 設置在指定Unix時間戳過期

    1. EXPIREAT key timestamp 設置到指定時間戳後過期
    2. PEXPIREAT key milliseconds-timestamp
  • 持久key,即取消過期

    1. PERSIST key持久key,即取消過期
  • 適用場景

    1. 多少秒過期,例如一個緩存數據失效
    2. PEXPIREAT key milliseconds-timestamp比如現在開始緩存數據,0點失效
  • Time to Live,key的剩餘生存時間

    1. TTL key查看key的剩餘生存時間,秒級別
    2. PTTL key查看key的剩餘生存時間,毫秒級別
    3. 命令返回結果:
      • key存在但沒有設置TTL,返回-1
      • key存在,但還在生存期內,返回剩餘的秒或者毫秒
      • key曾經存在,但已經消亡,返回-2(2.8版本之前返回-1)
  • 示例一:

設置鍵值s5:abc 20 秒後過期
# set s5 abc ex 20
查看s5剩餘過期時間
# ttl s5
127.0.0.1:6379[1]> set s5 abc ex 20
OK
127.0.0.1:6379[1]> ttl s5
(integer) 17
127.0.0.1:6379[1]> ttl s5
(integer) 15
127.0.0.1:6379[1]> ttl s5
(integer) 14
127.0.0.1:6379[1]> ttl s5
(integer) 12
127.0.0.1:6379[1]> ttl s5
(integer) 11
127.0.0.1:6379[1]> ttl s5
(integer) -2
127.0.0.1:6379[1]>
命令 意義
ttl s6 查看key爲s6的鍵過期時間,秒級別
pttl s6 查看key爲s6的鍵過期時間,毫秒級
setnx s6 6 設置key爲s6的值爲6
expire s6 60 設置key爲s6的鍵60秒後過期
persist s6 取消key爲s6的過期時間,即永不過期
EXPIREAT cache 1355292000 設置key爲cache在1355292000(秒)時間戳後過期
PEXPIREAT cache 1555555555005 設置key爲cache在1555555555005(毫秒)時間戳後過期

key操作

  • 語法:keys pattern查詢key
    1. pattern可以取如下值:
      1. *任意長度字符
      2. ?任意一個字符
      3. []字符集合,表示一個字符
命令 意義
keys * 查看當前庫中所有key鍵
keys s? 查看當前庫中以s開頭,只有兩個字符的key
keys s[13] 查看當前庫中以s開頭,只有兩個字符,且第二個字符時1或者3的key
keys s[1-3] 查看當前庫中以s開頭,只有兩個字符,且第二字符在[1,3]之間的key
keys s* 查看當前庫中以s開頭的字符
keys ?? 查看當前庫中是兩個字符組成的key
  • 其他相關命令
命令 意義
TYPE key key類型
EXISTS key key是否存在
RENAME key newkey 將key的建值重命名爲newkey
RENAMENX key newkey 將key的鍵值重命令爲newkey
DEL key [key ...] 將key鍵值對刪除

字符串獲取

命令 意義
GET key 獲取值
MGET key [key ...] 獲取多個給定的鍵的值
GETSET key value 返回舊值並設置新值,如果鍵不存在,就創建並賦值
STRLEN key 獲取key的value字符串長度
127.0.0.1:6379> keys *
1) "xdd"
2) "3"
3) "s2"
4) "s3"
5) "s4"
127.0.0.1:6379> get s4
"c"
127.0.0.1:6379> mget s2 s3 s1
1) "a"
2) "b"
3) (nil)
127.0.0.1:6379> strlen s2
(integer) 1
127.0.0.1:6379> getset s5 100
(nil)
127.0.0.1:6379> get s5
"100"
127.0.0.1:6379> keys *
1) "xdd"
2) "3"
3) "s2"
4) "s3"
5) "s4"
6) "s5"
127.0.0.1:6379>

字符串操作

  • 追加字符串

    1. APPEND key value追加字符串。如果鍵存在就追加;如果不存在就等同於SET key value
  • 獲取子字符串

    1. GETRANGE key start end索引值從0開始,支持負索引,-1表示最後一個字符。範圍是[start,end],start必須在end的左邊,否則返回空串
  • 覆蓋字符串

    1. SETRANGE key offset value從指定索引處開始覆蓋字符串,返回覆蓋後字符串長度。key不存在會創建新的。
  • 簡單示例

127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
(empty list or set)
127.0.0.1:6379[1]> append s2 abc
(integer) 3
127.0.0.1:6379[1]> get s2
"abc"
127.0.0.1:6379[1]> append s2 efg
(integer) 6
127.0.0.1:6379[1]> get s2
"abcefg"
127.0.0.1:6379[1]> getrange s2 1 3
"bce"
127.0.0.1:6379[1]> getrange s2 0 -1
"abcefg"
127.0.0.1:6379[1]> setrange s2 3 12
(integer) 6
127.0.0.1:6379[1]> get s2
"abc12g"
127.0.0.1:6379[1]> setrange s2 -1 123456
(error) ERR offset is out of range
127.0.0.1:6379[1]> get s2
"abc12g"
127.0.0.1:6379[1]> setrange s2 3 123456789
(integer) 12
127.0.0.1:6379[1]> get s2
"abc123456789"
127.0.0.1:6379[1]> setrange s7 3 abc
(integer) 6
127.0.0.1:6379[1]> get s7
"\x00\x00\x00abc"
127.0.0.1:6379[1]>

自增、自減

  • INCR key將key鍵對應的值增加1.必須是integer類型

  • DECR key將key鍵對應的值減少1,必須是integer類型

  • INCRby key decrement將key鍵對應的值增加decrement。

    1. decrement是數字,可以爲正負
    2. key對應的value必須是integer類型
  • DECRBY key decrement將key鍵對應的值減少加decrement。

    1. decrement是數字,可以爲正負
    2. key對應的value必須是integer類型
  • 簡單示例

127.0.0.1:6379[1]> flushdb
OK
127.0.0.1:6379[1]> keys *
(empty list or set)
127.0.0.1:6379[1]> set s1 ab1
OK
127.0.0.1:6379[1]> set s2 4
OK
127.0.0.1:6379[1]> incr s1
(error) ERR value is not an integer or out of range
127.0.0.1:6379[1]> incr s2
(integer) 5
127.0.0.1:6379[1]> incr s3
(integer) 1
127.0.0.1:6379[1]> incr s2
(integer) 6
127.0.0.1:6379[1]> get s2
"6"
127.0.0.1:6379[1]> keys *
1) "s3"
2) "s2"
3) "s1"
127.0.0.1:6379[1]> get s3
"1"
127.0.0.1:6379[1]> incrby s2 -10
(integer) -4
127.0.0.1:6379[1]> incrby s2 8
(integer) 4
127.0.0.1:6379[1]> decrby s2 -10
(integer) 14
127.0.0.1:6379[1]> get s2
"14"
127.0.0.1:6379[1]>

庫操作

  • redis-cli --help #查看幫助
  • redis-cli -n 2 # 登錄到第2號庫
    1. 登錄後命令上中切換庫
      • SELECT n選擇第n號庫
      • FLUSHDB 清除當前庫數據
      • FLUSHALL清除所有庫中的數據

位圖bitmap

  • 位圖不是真正的數類型,它是定義在字符串類型上,只不過把字符串按位操作

  • 一個字符串類型的值最多能存儲512M字節的內容,可以表示2322^{32}

    1. 位上限:
      • 512 = 292^9
      • 1M = 1024*1024=210+102^{10+10}
      • 1Byte = 8bit = 232^3bit
      • 29+10+10+3=232b=4294967296b2^{9+10+10+3}=2^{32}b=4294967296b,接近43憶個位
  • SETBIT key offset value設置某一位上的值

    1. offset 偏移量,從0開始
    2. value不寫,默認是0,只能是0或1
  • GETBIT key offset獲取某一位上的值

  • BITPOS key bit [start][end]返回指定值bit[0或者1]在指定區間上第一次出現的位置

    1. key 要查找的值所對應的鍵

    2. bit 只能是0或者1

    3. start 起始位置,默認每8個bit位所對應的索引爲1

    4. end 結束位置,注意:每8個bit位所對應的索引爲1

    5. 返回值:找到返回bit位的相對應0位置的偏移量。(注意此時不會按照每8個bit位作爲一個索引)找不到返回-1

    6. 示例:

      127.0.0.1:6379[1]> SETBIT ss 2 1
      (integer) 0
      127.0.0.1:6379[1]> SETBIT ss 18 1
      (integer) 0
      127.0.0.1:6379[1]> get ss
      " \x00 "
      127.0.0.1:6379[1]> BITPOS ss 1
      (integer) 2
      127.0.0.1:6379[1]> BITPOS ss 1 1
      (integer) 18
      127.0.0.1:6379[1]> BITPOS ss 1 2
      (integer) 18
      127.0.0.1:6379[1]> BITPOS ss 1 3
      (integer) -1
      127.0.0.1:6379[1]> STRLEN ss
      (integer) 3
      127.0.0.1:6379[1]>
      
  • BITCOUNT key [start] [end]統計指針位區間上值爲1的個數,從左向右從0開始,從右向左從-1開始,注意:官方start,end指的是位,測試後是字節(即,1字節等於8位)

    1. BITCOUNT testkey 0 0表示從索引爲0個字節到索引爲0個字節,就是第一個字節的統計
    2. BITCOUNT testkey 0 -1等同於BITCOUNT testkey
127.0.0.1:6379> set str1 abc
OK
127.0.0.1:6379> setbit str1 6 1
(integer) 0
127.0.0.1:6379> setbit str1 7 0
(integer) 1
127.0.0.1:6379> get str1
"bbc"
127.0.0.1:6379>

位操作

  • 對於一個或多個保存二進制位的字符串key進行位元操作,並將結果保存到destkey上operation可以是AND、OR、NOT、XOR這四種操作中的任意一種

  • BITOP AND destkey key [key ...]對一個或多個key求位與,並將結果保存到destkey

  • BITOP OR destkey key [key ...]對一個或多個key求位或,並將結果保存到destkey

  • BITOP XOR destkey key [key ...]對一個或多個key求位異或,並將結果保存到destkey

  • BITOP NOT destkey key對給定key求邏輯非,並將結果保存到destkey

  • 除了NOT操作之外,其他操作都可以接受一個或多個key作爲輸入,當BITOP處理不同長度的字符串時,較短的那個字符串所缺少的部分會被看作0.空的key也被看作是包含0的字符串序列

  • 示例:a位或b

127.0.0.1:6379> set s1 a
OK
127.0.0.1:6379> set s2 b
OK
127.0.0.1:6379> BITOP OR ss s1 s2
(integer) 1
127.0.0.1:6379> get ss
"c"
127.0.0.1:6379> set s3 中
OK
127.0.0.1:6379> get s3
"\xe4\xb8\xad"
127.0.0.1:6379> BITCOUNT s3
(integer) 13
127.0.0.1:6379>

redis_002

  • 位圖應用練習:
    1. 網站用戶上線次數統計(活躍用戶)
    2. 按天統計網站活躍用戶
  • 參考
    1. 網站用戶的上線次數統計(活躍用戶)
    2. 爲每一個用戶做上線記錄,某天登陸就標記一次。
    3. 用戶ID爲key,天作爲offset,上線置爲1,ID爲500的用戶,今年的第一天上線,第30天上線:
      • setbit u:500 1 1 #使用位圖標記,上線一次在對應天數上標記一次
      • setbit u:500 30 1
      • bitcount u:500 #統計一共上線次數
import redis

# 鏈接redis數據庫
db = redis.Redis("192.168.61.109",6379,db=2)
print(db.keys("*")) #查看所有keys

# user1
db.setbit("u:1",1,1) #第一天登錄,標記一次
db.setbit("u:1",30,1) #第30天登陸,標記一次
print("id爲500的用戶登錄次數:",db.bitcount("u:500")) #統計

# user2
db.setbit("u:2",110,1)
db.setbit("u:2",300,1)

# user101,模擬登錄,每3天登陸一次
for i in range(3,365,3):
    db.setbit("u:101",i,1)

# user102,模擬登錄,每2天登陸一次
for i in range(3,365,2):
    db.setbit("u:102",i,1)

userlist = db.keys("u*") #查詢所有用戶登錄信息
print(userlist)

active = [] #統計活躍用戶
inactive = [] #統計非活躍用戶

for u in userlist:
    logincount = db.bitcount(u)
    if logincount >100:
        active.append(u)
    else:
        inactive.append(u)

print("活躍用戶爲:{}".format(active))
print("非活躍用戶爲:{}".format(inactive))

redis_003

  • 2.按天統計網站活躍用戶
    1.這是日活、周活、月活等統計。天作爲key,用戶ID爲offset,上線設置爲1
    2. 一段時間內活躍用戶數:
    * setbit 20160602 15 1
    * setbit 20160601 123 1
    * setbit 20160606 123 1
    3. 求6月1日到6月10日的活躍用戶
    * BITOP OR 20160601-10 20160601 20160602 20160603 20160610
    * bitcount 20160601-10 #結果爲2

    127.0.0.1:6379> setbit 20160602 15 1
    (integer) 0
    127.0.0.1:6379> setbit 20160601 123 1
    (integer) 0
    127.0.0.1:6379> setbit 20160606 123 1
    (integer) 0
    127.0.0.1:6379> BITOP OR 20160601-10 20160601 20160602 20160603 20160610 
    (integer) 16
    127.0.0.1:6379> bitcount 20160601-10
    (integer) 2
    127.0.0.1:6379>
    

redis中的List列表模型

  • 其列表是基於雙向鏈表實現,列表頭尾增刪快,中間增刪慢

  • 元素是字符串類型

  • 元素可以重複出現

  • 索引支持正索引和負索引,從左至右從0開始,從右至左從-1開始

  • 命令說明

字母 說明
B Block阻塞
L Left左起,或指列表
R Right右起
X exist存在
  1. 查看長度

    • LLEN key返回列表元素個數
  2. 添加元素

    • LPUSH key value [value ...]從左邊向隊列中壓入元素
    • LPUSHX key value 從左邊向隊列加入元素,要求key必須存在(即列表已經存在)
    • RPUSH key value [value ...]從右邊向隊列中壓如數據
    • RPUSHX key value要求key存在(即列表已經存在),從右邊向隊列中加入元素
    • LINSERT key BEFORE|AFTER pivot value在列表中某個存在的值(pivot)前後後插入元素一次,key或pivot不存在,不進行任何操作
    127.0.0.1:6379> rpush lst 1 2 3 4 5
    (integer) 5
    127.0.0.1:6379> lrange lst 0 -1
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    5) "5"
    127.0.0.1:6379> LINSERT lst after 2 python
    (integer) 6
    127.0.0.1:6379> lrange lst 0 -1
    1) "1"
    2) "2"
    3) "python"
    4) "3"
    5) "4"
    6) "5"
    127.0.0.1:6379> LINSERT lst before 2 ruby
    (integer) 7
    127.0.0.1:6379> lrange lst 0 -1
    1) "1"
    2) "ruby"
    3) "2"
    4) "python"
    5) "3"
    6) "4"
    7) "5"
    127.0.0.1:6379>
    
  3. 彈出元素

    • LPOP key從左邊彈出列表中一個元素
    • RPOP key從右邊彈出列表中一個元素
  4. RPOPLPUSH source destination從源列表中右邊pop一個元素,從左邊加入到目標列表

    • source 源列表,需要從右邊彈出一個元素的列表
    • destination 目標列表,需要從左邊加入元素的列表
    127.0.0.1:6379> lpush s1 1 2 3 4 5 6
    (integer) 6
    127.0.0.1:6379> lpop s1
    "6"
    127.0.0.1:6379> lpush s2 11 12 13
    (integer) 3
    127.0.0.1:6379> RPOPLPUSH s1 s2
    "1"
    127.0.0.1:6379> RPOPLPUSH s1 s2
    "2"
    127.0.0.1:6379> rpop s2
    "11"
    127.0.0.1:6379> lpop s2
    "2"
    127.0.0.1:6379> lpop s2
    "1"
    127.0.0.1:6379>
    
  5. 元素訪問與修改

    • LRANGE key start stop返回列表中指定訪問的元素,例如LRANGE user 0 -1
    • LINDEX key index返回列表中指定索引位置的元素
    • LSET key index value設置列表中指定索引位置的元素值,index不能超界
  6. 移除元素

    • LREM key count value從左邊刪除列表中與value相等的元素刪除count個
      • count>0 從左至右搜索,移除與value相等的元素,數量至多爲count次
      • count<0 從右至左搜索,移除與value相等的元素,數量至多爲-count次
      • count = 0 移除列表中所有value值
    • LTRIM key start stop去除指定範圍外的元素
      • 保留範圍區間[start,stop]其餘全部移除
  7. 阻塞

    • 如果彈出的列表不存在或者爲空,就會阻塞
    • 超時時間設置爲0,就是永久阻塞,直到有數據可以彈出
    • 如果多個客戶端阻塞就在同一個列表上,使用First In First Service原則,先到先服務
    • BLPOP key [key ...] timeout列表右邊阻塞彈出一個元素。
      • key列表鍵名
      • timeout是超時秒數,爲0表示永久阻塞
      • 返回彈出列表名和彈出的值,如果有多個列表,會優先從第一個列表中彈出。
    • BRPOP key [key ...] timeout列表右邊阻塞彈出一個元素
    • BRPOPLPUSH source destination timeout從一個列表尾部阻塞彈出元素壓入到另一個列表的頭部
    • 應用場景
    # 阻塞式消息隊列
    BLPOP MyQueue 0 #阻塞獲取
    RPUSH MyQueue hello #向消息隊列添加值
    
  • 應用:微博某貼最後評論的50條
LPUSH u1234:forumid:comments "這是第1條評論"
LPUSH u1234:forumid:comments "這是第2條評論"
LPUSH u1234:forumid:comments "這是第3條評論"
# 使用LTRIM原因是,獲取後可以清楚多餘存放在redis中的評論
LTRIM u1234:forumid:comments 0 49

hash散列

  • 值是由field和value組成的map鍵值對
  • field和value都是字符串類型
  • 模型如下:
    redis_004
  1. 設置key
    • HSET key field value設置單個字段。field不存在就創建,存在覆蓋value
    • HSETNX key field value設置單個字段,要求field不存在。如果key不存在,相當於field也不存在
    • HMSET key field value [field value ...]設置多個字段
  2. 長度和判斷
    • HLEN key返回字段個數
    • HEXSTS key field判斷字段是否存在。key或者field不存在,返回0
  3. 獲取值
    • HGET key field返回字段值
    • HMGET key field [field ...]返回多個字段值
    • HGETALL key返回所有的鍵值對
    • HKEYS key返回所有字段名
    • HVALS key返回所有值
  4. 計算
    • HINCRBY key field increment在字段對應的值上進行整數的增量計算
    • HINCRBYFLOAT key field increment在字段對應的值上進行浮點數的增量計算
  5. 刪除
    • HDEL key field [field ...]刪除指定的字段
  • 簡單示例
127.0.0.1:6379> HINCRBY number x -50
(integer) -50
127.0.0.1:6379> HGET number x
"-50"
127.0.0.1:6379> HINCRBYFLOAT number x 3.14
"-46.86"
127.0.0.1:6379> HGET number x
"-46.86"
127.0.0.1:6379> hdel number x
(integer) 1
  • Hash用途

  • 節約內存空間

  • 每創建一個鍵,它就會爲這個鍵存儲一些附加的管理信息(比如這個鍵的類型,這個鍵最後一次被訪問的時間等等)

  • 所以數據庫裏面的鍵越多,redis數據庫服務器在儲存附加管理信息方面耗費的內存就越多,花在管理數據庫鍵上的CPU時間也會越多

redis_005

  • 應用場景
  1. 用戶緯度統計

    • 統計數包括:關注數、粉絲數、喜歡商品數、發帖數
    • 用戶爲key,不同維度爲Field,value爲統計數
    • 比如關注了5個人
    HSET user:100000 follow 5
    HINCRBY user:100000 follow 1
    
  2. 商品維度統計

    • 統計值包括喜歡數,評論數,購買數,瀏覽數等
    HSET item:58000 fav 500
    HINCRBY item:58000 fav 1
    
  3. 緩存用戶信息

    • 登錄後,反覆需要讀取用戶的常用信息,最好的方式就是緩存起來
    set user:001 "bob,18,20010101"
    mset user:001:name "bob" user:001:age 18 user:001:birthday "20010101" #不可取,重複值多
    hmset user:001 name "bob" age 18 birthday "20010101"
    

Set集合

  • 集合的元素是無序的、去重的、元素是字符串類型。
  1. 添加和刪除

    • SADD key member [member ...]增加一個或多個元素,元素已經存在將忽略
    • SREM key member [member ...]移除一個或多個元素,元素不存在自動忽略
    • SMOVE source destination member把元素從源集合移動到目標集合
  2. 查詢和長度

    • SCARD key返回集合中元素的個數。不需要遍歷。
    • SMEMBERS key返回集合中的所有元素。注意,如果集合中元素過多,應當避免使用該方法
    • SISMEMBER key number元素是否在集合中
    127.0.0.1:6379> SADD ss 1 2 1 2 3 5 6 8 5 6
    (integer) 6
    127.0.0.1:6379> SCARD ss
    (integer) 6
    127.0.0.1:6379> SMEMBERS ss
    1) "1"
    2) "2"
    3) "3"
    4) "5"
    5) "6"
    6) "8"
    127.0.0.1:6379> SREM ss 1 2 5
    (integer) 3
    127.0.0.1:6379> SMEMBERS ss
    1) "3"
    2) "6"
    3) "8"
    127.0.0.1:6379>
    
    • 注意:元素相同的兩個集合未必有相同的順序,去重且有序可使用有序集合
  3. 隨機獲取移除

    • SRANDMEMBER key [count]隨機返回結合中個雞丁個數的元素
      1. 如果count爲正數,且小於集合基數,那麼命令返回一個包含count個元素的數組,數組中的元素各不相同。如果count大於等於集合基數,那麼返回整個集合
      2. 如果count爲負數,那麼命令返回一個數組,數組中的元素可能會重複出現多次,而數組長度爲count的絕對值
      3. 如果count爲0 返回空
      4. 如果count不指定,隨機返回一個元素
    • SPOP key從集合中隨機移除一個元素並返回該元素
  4. 集合運算

    • 差集

      • SDIFF key [key ...]從第一個key的集合中去除其他集合和自己的交集部分
      • SDIFFSTORE destination key [key ...]將差集結果存儲在目標key中
      127.0.0.1:6379> sadd number1 123 456 789
      (integer) 3
      127.0.0.1:6379> sadd number2 123 456 999
      (integer) 3
      127.0.0.1:6379> sdiff number1 number2
      1) "789"
      127.0.0.1:6379>
      
    • 交集

      • SINTER key [key ...]取所有集合交集部分
      • SINTERSTORE destination key [key ...]將交集結果存儲在目標key中
      127.0.0.1:6379> sadd number1 123 456 789
      (integer) 3
      127.0.0.1:6379> sadd number2 123 456 999
      (integer) 3
      127.0.0.1:6379> sinter number1 number2
      1) "123"
      2) "456"
      127.0.0.1:6379>
      
    • 並集

      • SUNION key [key ...]取所有集合交集部分
      • SINTERSTORE destination key [key ...]將交集結果存儲在目標key中
      127.0.0.1:6379> sadd number1 123 456 789
      (integer) 3
      127.0.0.1:6379> sadd number2 123 456 999
      (integer) 3
      127.0.0.1:6379> SUNION number1 number2
      1) "123"
      2) "456"
      3) "789"
      4) "999"
      127.0.0.1:6379>
      
  • 應用場景示例:微博的共同關注
    1. 需求:當用戶訪問另一個用戶的時候,會顯示出兩個用戶共同關注哪些相同的用戶
    2. 設計:將每個用戶關注的用戶放在集合中,求交集即可
peter = {"john","jack","may"}
ben = {"john","jack","tom"}
那麼peter和ben的共同關注爲:
SINTER peter ben #結果爲:{“john","jack"}

SortedSet有序集合

  • 類似Set集合,有序的集合。每一個元素都關聯着一個浮點數分值(Score),並按照分值從小到大的順序排列集合中的元素。分值可以相同

redis_006

  1. 添加

    • ZADD key score member [score member ...]增加一個或多個元素。如果元素已經存在,則使用新的score
  2. 簡單查詢

    • ZCARD key返回集合的元素個數
    • ZCOUNT key min max返回指定score範圍元素的個數
    • ZSCORE key member顯示分值
  3. 修改

    • ZINCRBY key increment member增加或減少分值。increment爲負數就是減少
  4. 高級查詢

    • ZRANGE key start stop [WITHSCORES]返回指定索引區間元素(從大到小)
      • WITHSCORES 選項,帶上時返回序列中會攜帶分值
      • 有序集合裏面,如果score相同,則按照字典序lexicographical order排列
      • 默認按照score從大到小,如果需要score從小到大排列,使用ZREVRANGE
    • ZREVRANGE key start stop [WITHSCORES]返回指定索引區間元素(從小到大)
      • WITHSCORES 選項,帶上時返回序列中會攜帶分值
      • 如果score相同,則按照字典序lexicographical order的逆序排列
      • 默認按照score從大到小,如果需要score從小到大排列,使用ZRANGE
    • ZRANK key number返回元素的排名(索引)
    • ZREVRANK key number返回元素的逆序排名(索引)
    • ZRANGEBYSCORE key min max [WITHSCORES][LIMIT offset count]返回指定分數區間的元素
      • 返回score默認屬於[min,max]之間,元素按照score升序排列,score相同字典序
      • LIMIT中offset代表跳過多少個元素,count是返回幾個。類似於Mysql
      • 使用小括號,修改區間爲開區間,例如(5或者(10,5)
      • -inf和+inf表示負無窮和正無窮
    • ZREVRANGEBYSCORE key max min [WITHSCORES][LIMIT offset count]降序返回指定分數區間的元素
      • 返回score默認屬於[min,max]之間,元素按照score降序排列,score相同字典降序
    #添加過個值到employees中
    127.0.0.1:6379> ZADD employees 3500 jack 4000 peter 4000 john 4500 tom 2500 david
    (integer) 0
    #顯示employees集合所有key
    127.0.0.1:6379> zrange employees 0 -1
    1) "david"
    2) "jack"
    3) "john"
    4) "peter"
    5) "tom"
    #統計employees有序集合中分值在[3000,4000]的集合個數
    127.0.0.1:6379> ZCOUNT employees 3000 4000
    (integer) 3
    #添加值david 其分值爲3.2
    127.0.0.1:6379> zadd employees 3.2 david
    (integer) 0
    #查看david的分值
    127.0.0.1:6379> ZSCORE employees david
    "3.2000000000000002"
    #將jack的分值增加1.5
    127.0.0.1:6379> ZINCRBY employees 1.5 jack
    "3501.5"
    #將tom的分值減少500
    127.0.0.1:6379> zincrby employees -500 tom
    "4000"
    #帶分值顯示employees有序集合
    127.0.0.1:6379> zrange employees  0 -1 WITHSCORES
    1) "david"
    2) "3.2000000000000002"
    3) "jack"
    4) "3501.5"
    5) "john"
    6) "4000"
    7) "peter"
    8) "4000"
    9) "tom"
    10) "4000"
    #查詢peter的排名
    127.0.0.1:6379> zrank employees peter
    (integer) 3
    
    #逆序後的索引0到-1,即返回所有
    127.0.0.1:6379> zrevrange employees 0 -1 WITHSCORES
    1) "tom"
    2) "4000"
    3) "peter"
    4) "4000"
    5) "john"
    6) "4000"
    7) "jack"
    8) "3501.5"
    9) "david"
    10) "3.2000000000000002"
    #查詢peter的逆序排名
    127.0.0.1:6379> zrevrank employees peter
    (integer) 1
    127.0.0.1:6379>
    
    #高級查詢示例
    #查詢分值在[3500,4000]範圍內的鍵,升序排列顯示
    127.0.0.1:6379> zrangebyscore employees 3500 4000
    1) "jack"
    2) "john"
    3) "peter"
    4) "tom"
    127.0.0.1:6379> zrangebyscore employees (4000 5000 WITHSCORES
    (empty list or set)
    #查詢分值在(2000,5000)範圍內的鍵和值,升序排列顯示
    127.0.0.1:6379> zrangebyscore employees (2000 5000 WITHSCORES
    1) "jack"
    2) "3501.5"
    3) "john"
    4) "4000"
    5) "peter"
    6) "4000"
    7) "tom"
    8) "4000"
    #查詢分值在(2000,5000)範圍內的鍵和值,升序排列顯示,跳過第一個,最多顯示2個
    127.0.0.1:6379> zrangebyscore employees (2000 5000 WITHSCORES LIMIT 1 2
    1) "john"
    2) "4000"
    3) "peter"
    4) "4000"
    #查詢分值在[正無窮大,負無窮大]的鍵,降序顯示
    127.0.0.1:6379> zrevrangebyscore employees +inf -inf
    1) "tom"
    2) "peter"
    3) "john"
    4) "jack"
    5) "david"
    127.0.0.1:6379>
    
  5. 刪除

    • ZREM key member [member ...]移除一個或多個元素。元素不存在,自動忽略
    • ZREMRANGEBYRANK key start stop移除指定排名範圍的元素
    • ZREMRANGEBYSCORE key min max移除指定分值範圍的元素
    127.0.0.1:6379> zadd employees 1000 tom 2000 john 2000 jahh 3000 peter 4000 david 5000 xdd
    (integer) 6
    127.0.0.1:6379> ZRANGEBYSCORE employees -inf +inf WITHSCORES
    1) "tom"
    2) "1000"
    3) "jahh"
    4) "2000"
    5) "john"
    6) "2000"
    7) "peter"
    8) "3000"
    9) "david"
    10) "4000"
    11) "xdd"
    12) "5000"
    #刪除employees中分索引在[0,1]範圍內的值
    127.0.0.1:6379> ZREMRANGEBYRANK employees 0 1
    (integer) 2
    127.0.0.1:6379> ZRANGEBYSCORE employees -inf +inf WITHSCORES
    1) "john"
    2) "2000"
    3) "peter"
    4) "3000"
    5) "david"
    6) "4000"
    7) "xdd"
    8) "5000"
    #刪除employees集合中分值在[4000,5000]範圍內的值
    127.0.0.1:6379> ZREMRANGEBYSCORE employees 4000 5000
    (integer) 2
    127.0.0.1:6379> ZRANGEBYSCORE employees -inf +inf WITHSCORES
    1) "john"
    2) "2000"
    3) "peter"
    4) "3000"
    127.0.0.1:6379>
    
  6. 集合運算

    • 並集

    • ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] 並集運算

      • numkeys指定key的數量,必須
      • WEIGHTS選項,與前面設定的key對應,對應key中每一個score都要乘以這個權重
      • AGGREGATE選項,指定並集結果的聚合方式
      • SUM:將所有集合中某一個元素的score值之和作爲結果集中該成員的score值,默認行爲
      • MIN:將所有集合中某一個元素的score值中最小值作爲結果集中該成員的score值
      • MAX:將所有集合中某一個元素的score值中最大值作爲結果集中該成員的score值
      127.0.0.1:6379> zadd s1 70 tom 80 peter 60 john
      (integer) 3
      127.0.0.1:6379> zadd s2 90 peter 60 ben
      (integer) 2
      #求s1 s2的交集,s1的權重是1,s2的權重是1,默認合併後的分支使用sum求和方式
      127.0.0.1:6379> ZUNIONSTORE scores-all 2 s1 s2
      (integer) 4
      127.0.0.1:6379> ZRANGEBYSCORE scores-all -inf +inf WITHSCORES
      1) "ben"
      2) "60"
      3) "john"
      4) "60"
      5) "tom"
      6) "70"
      7) "peter"
      8) "170"
      #求s1 s2的交集,s1的權重是1,s2的權重是1,合併後的分支使用sum求和方式
      127.0.0.1:6379> ZUNIONSTORE scores-all1 2 s1 s2 aggregate sum
      (integer) 4
      127.0.0.1:6379> ZRANGEBYSCORE scores-all1 -inf +inf WITHSCORES
      1) "ben"
      2) "60"
      3) "john"
      4) "60"
      5) "tom"
      6) "70"
      7) "peter"
      8) "170"
      #求s1 s2的交集,s1的權重是1,s2的權重是0.5,合併後的分支使用sum求和方式
      127.0.0.1:6379> ZUNIONSTORE scores-all2 2 s1 s2 weights 1 0.5 aggregate sum
      (integer) 4
      127.0.0.1:6379> ZRANGEBYSCORE scores-all2 -inf +inf WITHSCORES
      1) "ben"
      2) "30"
      3) "john"
      4) "60"
      5) "tom"
      6) "70"
      7) "peter"
      8) "125"
      127.0.0.1:6379>
      
    • 交集

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

      • numkeys指定key的數量,必須
      • WEIGHTS選項,與前面設定的key對應,對應key中每一個score都要乘以這個權重
      • AGGREGATE選項,指定交集結果的聚合方式
      • SUM:將所有集合中某一個元素的score值之和作爲結果集中該成員的score值
      • MIN:將所有結合中某一個元素的score值中最小值作爲結果集中該成員的score值
      • MAX:將所有集合中某一個元素的score值中最大值作爲結果集中該成員的score值
  • 應用練習:音樂排行榜的實現

redis_007

  • 每首歌的歌名作爲元素(先補補考慮重複)

  • 每首歌的播放次數作爲分值

  • ZREVRANGE來獲取播放次數最多的歌曲(就是最多播放榜了,雲音樂熱歌榜,沒有競價,沒有權重)

  • python中redis庫是3.x版本代碼如下:

# redis版本3.x版本
import redis

r = redis.Redis(host="192.168.61.109",port=6379,db=3)
#清空數據庫
r.flushdb()
r.zadd("mboard",{"yellow":1,"rolling inthe deep":1,"happy":1,"just the way you are":1})
r.zadd("mboard",{"eye of the tiger":1,"billie jean":1,"say you say me":1,"payphone":1})
r.zadd("mboard",{"my heart will go on":1,"when you believe":1,"hero":1})

# 修改yellow的分值爲50
r.zincrby("mboard",50,"yellow")
r.zincrby("mboard",60,"rolling in the deep")
r.zincrby("mboard",68.8,"my heart will go on")
r.zincrby("mboard",70,"when you believe")

# 所有元素
allmusic = r.zrange("mboard",0,-1,withscores=True)
print(type(allmusic))

for m in allmusic:
    print(m)

print(" -"*30)
# 排行榜
musicboard = r.zrevrange("mboard",0,9,withscores=True)
print("歐美熱曲榜")

for i,m in enumerate(musicboard):
    print(i,*m)

redis_008

  • python中如果redis版本是2.x代碼如下:
# redis庫 2.x版本
import redis

r = redis.Redis(host='192.168.142.135', port=6379, db=3)

r.zadd('mboard','yellow',1,'rolling in the deep',1,'happy',1,'just the way you are',1)
r.zadd('mboard','eye of the tiger',1,'billie jean',1,'say you say me',1,'payphone',1)
r.zadd('mboard','my heart will go on',1,'when you believe',1,'hero',1)

r.zincrby('mboard','yellow',50)
r.zincrby('mboard','rolling in the deep',60)
r.zincrby('mboard','my heart will go on',68.8)
r.zincrby('mboard','when you believe',70)
# 所有元素
allmusic = r.zrange('mboard', 0, -1, withscores=True)
print(type(allmusic))
for m in allmusic:
    print(m)

print('-'*30)

# 排行榜
musicboard = r.zrevrange('mboard', 0, 9, True)
print('歐美熱曲榜')
for i, m in enumerate(musicboard):
    print(i, *m)
  • 應用場景
  1. 新浪微博翻頁

    • 新聞網站、播客、論壇、搜索引擎,頁面列表條目多,都需要分頁
    • blog這個key使用時間戳作爲score
      1. ZADD blog 1407000000 '今天天氣不錯'
      2. ZADD blog 1450000000 '今天我們學習Redis'
      3. ZADD blog 1560000000 '幾個Redis使用示例'
      4. ZREVRANGE blog 10 20顯示所有播客中最後的評論的條目
  2. 京東圖書暢銷榜

    • 統計單日榜,計算出周榜單、月榜單、年榜單
    每天統計一次榜單
    ZADD bk:it:01 1000 'java' 1500 'Redis' 2000 'haoop' 100 'scala' 80 'python'
    ZADD bk:it:02 1020 'java' 1500 'Redis' 2100 'haoop' 120 'python' 110 'scala'
    ZADD bk:it:03 1620 'java' 1510 'Redis' 3000 'haoop' 150 'storm' 120 'python'
    
    • 求銷售前10名
      1. 由於上面的日榜單是累計值,所以不能直接使用並集,要指定聚合運算爲MAX
    ZUNIONSTORE bk:it:01-03 3 bk:it:01 bk:it:02 bk:it:03 AGGREGATE MAX
    ZREVRANGE bk:it:01-03 0 9 WITHSCORES
    
    • 注意:如果參與並集元素的元素太多,會消耗大量內存和計算時間,可能會導致Redis服務阻塞,如果非要計算,選在空閒時間或備用服務器上計算。
    • 另一種統計
    ZADD bk:it:01 50 'java' 20 'Redis' 40 'haoop'
    ZADD bk:it:02 70 'java' 30 'Redis' 20 'haoop'
    ZADD bk:it:03 20 'java' 30 'Redis' 5 'haoop'
    每天統計當天銷量,統計IT類圖書一段時間的新銷售榜單
    ZUNIONSTORE bk:it:01-03 bk:it:01 bk:it:02 bk:it:03 AGGREGATE SUM
    ZREVRANGE bk:it:01-03 0 9 WITHSCORES
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章