程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SyBase數據庫 >> SyBase教程 >> Redis數據類型之string類型

Redis數據類型之string類型

編輯:SyBase教程

Redis數據類型之string類型


 

string類型-特點

string 是最簡單的類型,你可以理解成與 Memcached 是一模一樣的類型,一個 key對應一個value,其上支持的操作與 Memcached 的操作類似。但它的功能更豐富。
string 類型是二進制安全的。意思是redis的string可以包含任何數據,比如jpg圖片或者序列化的對象;從內部實現來看其實string可以看作byte數組,最大上限是1G字節。
另外string類型可以被部分命令按 int處理,比如 incr等命令,如果只用 string類型,redis就可以被看作加上持久化特性的 memcached。 當然 redis對string類型的操作比 memcached還是多很多的。
在list、set和zset中包含的獨立元素類型都是string元素。

string常見命令

SET
SET key value [EX seconds] [PX milliseconds] [NX|XX]
將字符串值value關聯到key。
如果key已經持有其他值,SET就覆寫就值,無視類型。
對於某個原本帶有生存時間(TTL)的鍵來說,當SET命令成功在這個鍵上執行時,這個鍵原有的TTL將被清除。
SET 命令的行為可以通過一系列參數來修改:
   EX second :設置鍵的過期時間為 second 秒。SET key value EX second 效果等同於 SETEX key second value 。
   PX millisecond :設置鍵的過期時間為 millisecond 毫秒。SET key value PX millisecond 效果等同於 PSETEX key millisecond value 。
   NX :只在鍵不存在時,才對鍵進行設置操作。SET key value NX 效果等同於 SETNX key value 。
   XX :只在鍵已經存在時,才對鍵進行設置操作。
時間復雜度: O(1)
返回值:SET 在設置操作成功完成時,才返回 OK 。如果設置了 NX 或者 XX ,但因為條件沒達到而造成設置操作未執行,那麼命令返回空批量回復(NULL Bulk Reply) 。


# 對不存在的key進行設置

127.0.0.1:6379[15]> SET key_1 1
OK
127.0.0.1:6379[15]> GET key_1
"1"


# 對已存在的key進行設置

127.0.0.1:6379[15]> SET key_1 "key_1"
OK
127.0.0.1:6379[15]> GET key_1
"key_1"


# 使用EX選項

127.0.0.1:6379[15]> SET key_2 2 EX 86400
OK
127.0.0.1:6379[15]> GET key_2
"2"
127.0.0.1:6379[15]> TTL key_2
(integer) 86387
127.0.0.1:6379[15]> SET key_3 3
OK


# 使用PX選項

127.0.0.1:6379[15]> SET key_3 3 PX 86400
OK
127.0.0.1:6379[15]> GET key_3
"3"
127.0.0.1:6379[15]> PTTL key_3
(integer) 68219


# 使用NX選項

127.0.0.1:6379[15]> SET key_4 4 NX
OK
127.0.0.1:6379[15]> GET key_4
"4"
127.0.0.1:6379[15]> SET key_4 "key_4" NX 
(nil)
127.0.0.1:6379[15]> GET key_4
"4"


# 使用XX選項

127.0.0.1:6379[15]> EXISTS key_5
(integer) 0
127.0.0.1:6379[15]> SET key_5 5 XX
(nil)
127.0.0.1:6379[15]> SET key_5 5
OK
127.0.0.1:6379[15]> SET key_5 "key_5" XX
OK
127.0.0.1:6379[15]> GET key_5
"key_5"


# NX 或 XX 可以和 EX 或者 PX 組合使用

127.0.0.1:6379[15]>  SET key-with-expire-and-NX "hello" EX 10086 NX
OK
127.0.0.1:6379[15]> GET key-with-expire-and-NX
"hello"
127.0.0.1:6379[15]>  TTL key-with-expire-and-NX
(integer) 10075
127.0.0.1:6379[15]> SET key-with-pexpire-and-XX "old value"
OK
127.0.0.1:6379[15]> SET key-with-pexpire-and-XX "new value" PX 123321 XX
OK
127.0.0.1:6379[15]>  GET key-with-pexpire-and-XX
"new value"
127.0.0.1:6379[15]>  PTTL key-with-pexpire-and-XX
(integer) 107932


# EX 和 PX 可以同時出現,但後面給出的選項會覆蓋前面給出的選項

127.0.0.1:6379[15]>  SET key "value" EX 1000 PX 5000000
OK
127.0.0.1:6379[15]> TTL key
(integer) 4993  # 這是 PX 參數設置的值
127.0.0.1:6379[15]>  SET another-key "value" PX 5000000 EX 1000
OK
127.0.0.1:6379[15]>  TTL another-key
(integer) 995   # 這是 EX 參數設置的值

SETNX
SETNX key value
將 key 的值設為 value ,當且僅當 key 不存在。
若給定的 key 已經存在,則SETNX 不做任何動作。
SETNX 是『SET if Not eXists』(如果不存在,則 SET) 的簡寫。
時間復雜度: O(1)
返回值:
  設置成功,返回 1 。
  設置失敗,返回 0 。

127.0.0.1:6379[15]> EXISTS key_1
(integer) 0
127.0.0.1:6379[15]> SETNX key_1 1
(integer) 1
127.0.0.1:6379[15]> SETNX key_1 "key_1"
(integer) 0
127.0.0.1:6379[15]> GET key_1
"1"

SETEX
SETEX key seconds value
將值 value 關聯到 key ,並將 key 的生存時間設為 seconds (以秒為單位)。
如果 key 已經存在,SETEX 命令將覆寫舊值。
這個命令類似於以下兩個命令:
SET key value
EXPIRE key seconds # 設置生存時間
不同之處是,SETEX 是一個原子性 (atomic) 操作,關聯值和設置生存時間兩個動作會在同一時間內完成,該命令在 Redis 用作緩存時,非常實用。
時間復雜度: O(1)
返回值:
  設置成功時返回 OK 。
  當 seconds 參數不合法時,返回一個錯誤。


# 在 key 不存在時進行 SETEX

127.0.0.1:6379[15]> SETEX key_1 86400 1
OK
127.0.0.1:6379[15]> GET key_1
"1"
127.0.0.1:6379[15]> TTL key_1
(integer) 86390     # 剩余生存時間


# key 已經存在時,SETEX 覆蓋舊值

127.0.0.1:6379[15]> SET key_2 2
OK
127.0.0.1:6379[15]> SETEX key_2 86400 "key_2"
OK
127.0.0.1:6379[15]> GET key_2
"key_2"
127.0.0.1:6379[15]> TTL key_2
(integer) 86388

PSETEX
PSETEX key milliseconds value
這個命令和SETEX 命令相似,但它以毫秒為單位設置 key 的生存時間,而不是像SETEX 命令那樣,以秒為單位。
時間復雜度: O(1)
返回值: 設置成功時返回 OK 。

127.0.0.1:6379[15]> PSETEX key_1 80000 1
OK
127.0.0.1:6379[15]> PTTL key_1
(integer) 70167
127.0.0.1:6379[15]> GET key_1
"1"

SETRANGE
SETRANGE key offset value
用 value 參數覆寫 (overwrite) 給定 key 所儲存的字符串值,從偏移量 offset 開始。
不存在的 key 當作空白字符串處理。
SETRANGE 命令會確保字符串足夠長以便將 value 設置在指定的偏移量上,如果給定 key 原來儲存的字符串長度比偏移量小 (比如字符串只有 5 個字符長,但你設置的 offset 是 10 ),那麼原字符和偏移量之間的空白將用零字節 (zerobytes, “\x00” ) 來填充。
注意你能使用的最大偏移量是 2^29-1(536870911) ,因為 Redis 字符串的大小被限制在 512 兆 (megabytes)以內。如果你需要使用比這更大的空間,你可以使用多個 key 。

當生成一個很長的字符串時,Redis 需要分配內存空間,該操作有時候可能會造成服務器阻塞 (block)。在 2010 年的 Macbook Pro 上,設置偏移量為 536870911(512MB 內存分配),耗費約 300 毫秒,設置偏移量為 134217728(128MB 內存分配),耗費約 80 毫秒,設置偏移量 33554432(32MB 內存分配),耗費約 30 毫秒,設置偏移量為 8388608(8MB 內存分配),耗費約 8 毫秒。注意若首次內存分配成功之後,再對同一個 key 調用SETRANGE 操作,無須再重新內存。
時間復雜度:對小 (small) 的字符串,平攤復雜度 O(1)。(關於什麼字符串是” 小” 的,請參考APPEND 命令)否則為 O(M),M 為 value 參數的長度。
返回值: 被SETRANGE 修改之後,字符串的長度。
因為有了SETRANGE 和GETRANGE 命令,你可以將 Redis 字符串用作具有 O(1) 隨機訪問時間的線性數組,這在很多真實用例中都是非常快速且高效的儲存方式,具體請參考APPEND 命令的『模式:時間序列』部分。

127.0.0.1:6379[15]> SET greeting "hello world"
OK
127.0.0.1:6379[15]> SETRANGE greeting 6 "Redis"
(integer) 11
127.0.0.1:6379[15]> GET greeting
"hello Redis"
127.0.0.1:6379[15]> EXISTS empty_string
(integer) 0
127.0.0.1:6379[15]> SETRANGE empty_string 5 "Redis!" 
(integer) 11
127.0.0.1:6379[15]> GET empty_string
"\x00\x00\x00\x00\x00Redis!"

GETRANGE
GETRANGE key start end
返回 key 中字符串值的子字符串,字符串的截取范圍由 start 和 end 兩個偏移量決定 (包括 start 和 end在內)。
負數偏移量表示從字符串最後開始計數,-1 表示最後一個字符,-2 表示倒數第二個,以此類推。GETRANGE 通過保證子字符串的值域 (range) 不超過實際字符串的值域來處理超出范圍的值域請求。
時間復雜度:
  O(N),N 為要返回的字符串的長度。
  復雜度最終由字符串的返回值長度決定,但因為從已有字符串中取出子字符串的操作非常廉價(cheap),所以對於長度不大的字符串,該操作的復雜度也可看作 O(1)。
返回值: 截取得出的子字符串。

127.0.0.1:6379[15]> SET greeting "hello, my friend"
OK
127.0.0.1:6379[15]>  GETRANGE greeting 0 4      # 返回索引 0-4 的字符,包括 4。
"hello"
127.0.0.1:6379[15]>  GETRANGE greeting -1 -5    # 不支持回繞操作
""
127.0.0.1:6379[15]>  GETRANGE greeting -3 -1    # 負數索引
"end"
127.0.0.1:6379[15]> GETRANGE greeting 0 -1      # 從第一個到最後一個
"hello, my friend"
127.0.0.1:6379[15]>  GETRANGE greeting 0 1008611    # 值域范圍不超過實際字符串,超過部分自動被忽略
"hello, my friend"

注意:GETRANGE和SETRANGE都是單字節操作,對中文支持並不友好。

APPEND
APPEND key value
如果 key 已經存在並且是一個字符串,APPEND 命令將 value 追加到 key 原來的值的末尾。
如果 key 不存在,APPEND 就簡單地將給定 key 設為 value ,就像執行 SET key value 一樣。
時間復雜度: 平攤 O(1)
返回值: 追加 value 之後,key 中字符串的長度。

127.0.0.1:6379[15]> EXISTS myphone
(integer) 0
127.0.0.1:6379[15]> APPEND myphone "nokia"
(integer) 5
127.0.0.1:6379[15]>  APPEND myphone " - 1110" 
(integer) 12
127.0.0.1:6379[15]> GET myphone
"nokia - 1110"

時間序列 (Time series)
APPEND 可以為一系列定長 (fixed-size) 數據 (sample) 提供一種緊湊的表示方式,通常稱之為時間序列。每當一個新數據到達的時候,執行以下命令:
APPEND timeseries “fixed-size sample”
然後可以通過以下的方式訪問時間序列的各項屬性:
  STRLEN 給出時間序列中數據的數量
  GETRANGE 可以用於隨機訪問。只要有相關的時間信息的話,我們就可以在 Redis 2.6 中使用 Lua腳本和GETRANGE 命令實現二分查找。
  SETRANGE 可以用於覆蓋或修改已存在的的時間序列。
這個模式的唯一缺陷是我們只能增長時間序列,而不能對時間序列進行縮短,因為 Redis 目前還沒有對字符串進行修剪 (tirm) 的命令,但是,不管怎麼說,這個模式的儲存方式還是可以節省下大量的空間。

Note: 可以考慮使用 UNIX 時間戳作為時間序列的鍵名,這樣一來,可以避免單個 key 因為保存過大的時間序列而占用大量內存,另一方面,也可以節省下大量命名空間。

127.0.0.1:6379[15]> APPEND ts "0043"
(integer) 4
127.0.0.1:6379[15]> APPEND ts "0035"
(integer) 8
127.0.0.1:6379[15]> GETRANGE ts 0 3
"0043"
127.0.0.1:6379[15]> GETRANGE ts 4 7
"0035"

GET
GET key
返回 key 所關聯的字符串值。
如果 key 不存在那麼返回特殊值 nil 。
假如 key 儲存的值不是字符串類型,返回一個錯誤,因為GET 只能用於處理字符串值。
時間復雜度: O(1)
返回值:
  當 key 不存在時,返回 nil ,否則,返回 key 的值。
  如果 key 不是字符串類型,那麼返回一個錯誤。

127.0.0.1:6379[15]> GET key_1
(nil)
127.0.0.1:6379[15]> SET key_1 1
OK
127.0.0.1:6379[15]> get key_1
"1" 

MSET
MSET key value [key value …]
同時設置一個或多個 key-value 對。
如果某個給定 key 已經存在,那麼MSET 會用新值覆蓋原來的舊值,如果這不是你所希望的效果,請考慮使用MSETNX 命令:它只會在所有給定 key 都不存在的情況下進行設置操作。
MSET 是一個原子性 (atomic) 操作,所有給定 key 都會在同一時間內被設置,某些給定 key 被更新而另一些給定 key 沒有改變的情況,不可能發生。
時間復雜度: O(N),N 為要設置的 key 數量。
返回值: 總是返回 OK (因為 MSET 不可能失敗)

127.0.0.1:6379[15]> MSET key_1 1 key_2 2 key_3 3 
OK
127.0.0.1:6379[15]> MGET key_1 key_2 key_3
1) "1"
2) "2"
3) "3"

MGET
MGET key [key …]
返回所有 (一個或多個) 給定 key 的值。
如果給定的 key 裡面,有某個 key 不存在,那麼這個 key 返回特殊值 nil 。因此,該命令永不失敗。
時間復雜度: O(N) , N 為給定 key 的數量。
返回值: 一個包含所有給定 key 的值的列表。

127.0.0.1:6379[15]> MSET key_1 1 key_2 2 key_3 3
OK
127.0.0.1:6379[15]> MGET key_1 key_2 key_4
1) "1"
2) "2"
3) (nil)    

MSETNX
MSETNX key value [key value …]
同時設置一個或多個 key-value 對,當且僅當所有給定 key 都不存在。
即使只有一個給定 key 已存在,MSETNX 也會拒絕執行所有給定 key 的設置操作。
MSETNX 是原子性的,因此它可以用作設置多個不同 key 表示不同字段 (field) 的唯一性邏輯對象 (uniquelogic object),所有字段要麼全被設置,要麼全不被設置。
時間復雜度: O(N),N 為要設置的 key 的數量。
返回值:
  當所有 key 都成功設置,返回 1 。
  如果所有給定 key 都設置失敗 (至少有一個 key 已經存在),那麼返回 0 。

127.0.0.1:6379[15]> MSETNX rmdbs "MySQL" nosql "MongoDB" key-value-store "redis"
(integer) 1
127.0.0.1:6379[15]> MGET rmdbs nosql key-value-store
1) "MySQL"
2) "MongoDB"
3) "redis"
127.0.0.1:6379[15]> MSETNX rmdbs "Sqlite" language "python"
(integer) 0
127.0.0.1:6379[15]> EXISTS language
(integer) 0
127.0.0.1:6379[15]> GET rmdbs
"MySQL"

GETSET
GETSET key value
將給定 key 的值設為 value ,並返回 key 的舊值 (old value)。
當 key 存在但不是字符串類型時,返回一個錯誤。
時間復雜度: O(1)
返回值:
  返回給定 key 的舊值。
  當 key 沒有舊值時,也即是,key 不存在時,返回 nil 。

127.0.0.1:6379[15]> EXISTS db
(integer) 0
127.0.0.1:6379[15]>  GETSET db mongodb
(nil)
127.0.0.1:6379[15]>  GET db
"mongodb"
127.0.0.1:6379[15]>  GETSET db redis
"mongodb"
127.0.0.1:6379[15]>  GET db
"redis"

GETSET 可以和INCR 組合使用,實現一個有原子性 (atomic) 復位操作的計數器 (counter)。
舉例來說,每次當某個事件發生時,進程可能對一個名為 mycount 的 key 調用INCR 操作,通常我們還要在一個原子時間內同時完成獲得計數器的值和將計數器值復位為 0 兩個操作。
可以用命令 GETSET mycounter 0 來實現這一目標。

127.0.0.1:6379[15]> INCR mycount
(integer) 12
127.0.0.1:6379[15]> GETSET mycount 0
"12"
127.0.0.1:6379[15]> GET mycount
"0"

STRLEN
STRLEN key
返回 key 所儲存的字符串值的長度。
當 key 儲存的不是字符串值時,返回一個錯誤。
復雜度: O(1)
返回值:
  字符串值的長度。
  當 key 不存在時,返回 0 。

127.0.0.1:6379[15]> SET mykey "Hello world"
OK
127.0.0.1:6379[15]> STRLEN mykey
(integer) 11
127.0.0.1:6379[15]>  STRLEN nonexisting
(integer) 0

INCR
INCR key
將 key 中儲存的數字值增一。
如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行INCR 操作。
如果值包含錯誤的類型,或字符串類型的值不能表示為數字,那麼返回一個錯誤。
本操作的值限制在 64 位 (bit) 有符號數字表示之內。
時間復雜度: O(1)
返回值: 執行INCR 命令之後 key 的值。

127.0.0.1:6379[15]>  SET page_view 20
OK
127.0.0.1:6379[15]>  INCR page_view
(integer) 21
127.0.0.1:6379[15]>  GET page_view
"21"

模式:計數器
計數器是 Redis 的原子性自增操作可實現的最直觀的模式了,它的想法相當簡單:每當某個操作發生時,向Redis 發送一個INCR 命令。
比如在一個 web 應用程序中,如果想知道用戶在一年中每天的點擊量,那麼只要將用戶 ID 以及相關的日期信息作為鍵,並在每次用戶點擊頁面時,執行一次自增操作即可。
比如用戶名是 peter,點擊時間是 2012 年 3 月 22 日,那麼執行命令 INCR peter::2012.3.22 。
可以用以下幾種方式擴展這個簡單的模式:
  可以通過組合使用INCR 和EXPIRE ,來達到只在規定的生存時間內進行計數 (counting) 的目的。
  客戶端可以通過使用GETSET 命令原子性地獲取計數器的當前值並將計數器清零,更多信息請參考GETSET命令。
  使用其他自增/自減操作,比如DECR 和INCRBY ,用戶可以通過執行不同的操作增加或減少計數器的值,比如在游戲中的記分器就可能用到這些命令。
模式:限速器
限速器是特殊化的計算器,它用於限制一個操作可以被執行的速率 (rate)。
限速器的典型用法是限制公開 API的請求次數,以下是一個限速器實現示例,它將 API的最大請求數限制在每個 IP地址每秒鐘十個之內:

FUNCTION LIMIT_API_CALL(ip)
ts = CURRENT_UNIX_TIME()
keyname = ip+":"+ts
current = GET(keyname)
IF current != NULL AND current > 10 THEN
ERROR "too many requests per second"
END

IF current == NULL THEN
MULTI
INCR(keyname, 1)
EXPIRE(keyname, 1)
EXEC
ELSE
INCR(keyname, 1)
END
PERFORM_API_CALL()

這個實現每秒鐘為每個 IP 地址使用一個不同的計數器,並用EXPIRE 命令設置生存時間 (這樣 Redis 就會負責自動刪除過期的計數器)。
注意,我們使用事務打包執行INCR 命令和EXPIRE 命令,避免引入競爭條件,保證每次調用 API時都可以正確地對計數器進行自增操作並設置生存時間。
以下是另一個限速器實現:

FUNCTION LIMIT_API_CALL(ip):
current = GET(ip)
IF current != NULL AND current > 10 THEN
ERROR "too many requests per second"
ELSE
value = INCR(ip)
IF value == 1 THEN
EXPIRE(ip,1)
END
PERFORM_API_CALL()
END

這個限速器只使用單個計數器,它的生存時間為一秒鐘,如果在一秒鐘內,這個計數器的值大於 10 的話,那麼訪問就會被禁止。
這個新的限速器在思路方面是沒有問題的,但它在實現方面不夠嚴謹,如果我們仔細觀察一下的話,就會發現在INCR 和EXPIRE 之間存在著一個競爭條件,假如客戶端在執行INCR 之後,因為某些原因 (比如客戶端失敗) 而忘記設置EXPIRE 的話,那麼這個計數器就會一直存在下去,造成每個用戶只能訪問 10 次,噢,這簡直是個災難!
要消滅這個實現中的競爭條件,我們可以將它轉化為一個 Lua 腳本,並放到 Redis 中運行

local current
current = redis.call("incr",KEYS[1])
if tonumber(current) == 1 then
redis.call("expire",KEYS[1],1)
end

通過將計數器作為腳本放到 Redis上運行,我們保證了INCR 和EXPIRE 兩個操作的原子性,現在這個腳本實現不會引入競爭條件,它可以運作的很好。
還有另一種消滅競爭條件的方法,就是使用 Redis 的列表結構來代替INCR 命令,這個方法無須腳本支持,因此它在 Redis 2.6 以下的版本也可以運行得很好:

FUNCTION LIMIT_API_CALL(ip)
current = LLEN(ip)
IF current > 10 THEN
ERROR "too many requests per second"
ELSE
IF EXISTS(ip) == FALSE
MULTI
RPUSH(ip,ip)
EXPIRE(ip,1)
EXEC
ELSE
RPUSHX(ip,ip)
END
PERFORM_API_CALL()
END

新的限速器使用了列表結構作為容器,LLEN 用於對訪問次數進行檢查,一個事務包裹著RPUSH和EXPIRE 兩個命令,用於在第一次執行計數時創建列表,並正確設置地設置過期時間,最後,RPUSHX在後續的計數操作中進行增加操作。

INCRBY
INCRBY key increment
將 key 所儲存的值加上增量 increment 。
如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行INCRBY 命令。
如果值包含錯誤的類型,或字符串類型的值不能表示為數字,那麼返回一個錯誤。
本操作的值限制在 64 位 (bit) 有符號數字表示之內。
關於遞增 (increment) / 遞減 (decrement) 操作的更多信息,參見INCR 命令。
時間復雜度: O(1)
返回值: 加上 increment 之後,key 的值。

127.0.0.1:6379[15]> SET rank 50
OK
127.0.0.1:6379[15]> INCRBY rank 20
(integer) 70
127.0.0.1:6379[15]> EXISTS counter
(integer) 0
127.0.0.1:6379[15]> INCRBY counter 30
(integer) 30

INCRBYFLOAT
INCRBYFLOAT key increment
為 key 中所儲存的值加上浮點數增量 increment 。
如果 key 不存在,那麼INCRBYFLOAT 會先將 key 的值設為 0 ,再執行加法操作。
如果命令執行成功,那麼 key 的值會被更新為(執行加法之後的)新值,並且新值會以字符串的形式返回給調用者。
無論是 key 的值,還是增量 increment ,都可以使用像 2.0e7 、3e5 、90e-2 那樣的指數符號 (exponentialnotation) 來表示,但是,執行 INCRBYFLOAT 命令之後的值總是以同樣的形式儲存,也即是,它們總是由一個數字,一個(可選的)小數點和一個任意位的小數部分組成(比如 3.14 、69.768 ,諸如此類),小數部分尾隨的 0 會被移除,如果有需要的話,還會將浮點數改為整數(比如 3.0 會被保存成 3 ) 。
除此之外,無論加法計算所得的浮點數的實際精度有多長,INCRBYFLOAT 的計算結果也最多只能表示小數點的後十七位。
當以下任意一個條件發生時,返回一個錯誤:
  key 的值不是字符串類型 (因為 Redis 中的數字和浮點數都以字符串的形式保存,所以它們都屬於字符串類型)
  key 當前的值或者給定的增量 increment 不能解釋 (parse) 為雙精度浮點數 (double precision floatingpoint number)
時間復雜度: O(1)
返回值: 執行命令之後 key 的值。

127.0.0.1:6379[15]> SET mykey 10.50
OK
127.0.0.1:6379[15]> INCRBYFLOAT mykey 0.1
"10.6"


# 值和增量都是指數符號

127.0.0.1:6379[15]>  SET mykey 314e-2
OK
127.0.0.1:6379[15]> GET mykey   # 用 SET 設置的值可以是指數符號
"314e-2"
127.0.0.1:6379[15]> INCRBYFLOAT mykey 0     # 但執行 INCRBYFLOAT 之後格式會被改成非指數符號
"3.14"
127.0.0.1:6379[15]>  SET mykey 3
OK
127.0.0.1:6379[15]>  INCRBYFLOAT mykey 1.1
"4.1"
127.0.0.1:6379[15]>  SET mykey 3.0  # 後跟的 0 會被移除
OK
127.0.0.1:6379[15]>  GET mykey
"3.0"
127.0.0.1:6379[15]>  INCRBYFLOAT mykey 1.000000000000000000000  # 但 INCRBYFLOAT 會將無用的 0 忽略掉,有需要的話,將浮點變為整數
"4"
127.0.0.1:6379[15]>  GET mykey
"4"

DECR
DECR key
將 key 中儲存的數字值減一。
如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行DECR 操作。
如果值包含錯誤的類型,或字符串類型的值不能表示為數字,那麼返回一個錯誤。
本操作的值限制在 64 位 (bit) 有符號數字表示之內。
關於遞增 (increment) / 遞減 (decrement) 操作的更多信息,請參見INCR 命令。
時間復雜度: O(1)
返回值: 執行DECR 命令之後 key 的值。

127.0.0.1:6379[15]>  SET failure_times 10
OK
127.0.0.1:6379[15]> DECR failure_times
(integer) 9
127.0.0.1:6379[15]>  EXISTS count
(integer) 0
127.0.0.1:6379[15]> DECR count
(integer) -1

DECRBY
DECRBY key decrement
將 key 所儲存的值減去減量 decrement 。
如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行DECRBY 操作。
如果值包含錯誤的類型,或字符串類型的值不能表示為數字,那麼返回一個錯誤。
本操作的值限制在 64 位 (bit) 有符號數字表示之內。
關於更多遞增 (increment) / 遞減 (decrement) 操作的更多信息,請參見INCR 命令。
時間復雜度: O(1)
返回值: 減去 decrement 之後,key 的值。

127.0.0.1:6379[15]> SET count 100
OK
127.0.0.1:6379[15]>  DECRBY count 20
(integer) 80
127.0.0.1:6379[15]>  EXISTS pages
(integer) 0
127.0.0.1:6379[15]>  DECRBY pages 10
(integer) -10

SETBIT
SETBIT key offset value
對 key 所儲存的字符串值,設置或清除指定偏移量上的位 (bit)。
位的設置或清除取決於 value 參數,可以是 0 也可以是 1 。
當 key 不存在時,自動生成一個新的字符串值。
字符串會進行伸展 (grown) 以確保它可以將 value 保存在指定的偏移量上。當字符串值進行伸展時,空白位置以 0 填充。
offset 參數必須大於或等於 0 ,小於 2^32 (bit 映射被限制在 512 MB 之內)。
時間復雜度: O(1)
返回值: 指定偏移量原來儲存的位。

127.0.0.1:6379[15]> SETBIT bit 10086 1
(integer) 0
127.0.0.1:6379[15]>  GETBIT bit 10086
(integer) 1
127.0.0.1:6379[15]>  GETBIT bit 100
(integer) 0

Warning: 對使用大的 offset 的SETBIT 操作來說,內存分配可能造成 Redis 服務器被阻塞。具體參考SETRANGE 命令,warning(警告) 部分。

GETBIT
GETBIT key offset
對 key 所儲存的字符串值,獲取指定偏移量上的位 (bit)。
當 offset 比字符串值的長度大,或者 key 不存在時,返回 0 。
時間復雜度: O(1)
返回值: 字符串值指定偏移量上的位 (bit)。

127.0.0.1:6379[15]> EXISTS bit
(integer) 0
127.0.0.1:6379[15]> GETBIT bit 10086
(integer) 0
127.0.0.1:6379[15]> SETBIT bit 10086 1
(integer) 0
127.0.0.1:6379[15]> GETBIT bit 10086
(integer) 1

BITOP
BITOP operation destkey key [key …]
對一個或多個保存二進制位的字符串 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 的字符串序列。
時間復雜度: O(N)
返回值: 保存到 destkey 的字符串的長度,和輸入 key 中最長的字符串長度相等。

127.0.0.1:6379[15]> SETBIT bits-1 0 1
(integer) 1
127.0.0.1:6379[15]>  SETBIT bits-1 3 1
(integer) 0
127.0.0.1:6379[15]>  SETBIT bits-2 0 1 
(integer) 0
127.0.0.1:6379[15]>  SETBIT bits-2 1 1
(integer) 0
127.0.0.1:6379[15]>  SETBIT bits-2 3 1
(integer) 0
127.0.0.1:6379[15]>  BITOP AND and-result bits-1 bits-2
(integer) 1
127.0.0.1:6379[15]>  GETBIT and-result 0
(integer) 1
127.0.0.1:6379[15]> GETBIT and-result 1
(integer) 0
127.0.0.1:6379[15]>  GETBIT and-result 2
(integer) 0
127.0.0.1:6379[15]>  GETBIT and-result 3
(integer) 1

Note: BITOP 的復雜度為 O(N) ,當處理大型矩陣 (matrix) 或者進行大數據量的統計時,最好將任務指派到附屬節點 (slave) 進行,避免阻塞主節點。

BITCOUNT
BITCOUNT key [start] [end]
計算給定字符串中,被設置為 1 的比特位的數量。
一般情況下,給定的整個字符串都會被進行計數,通過指定額外的 start 或 end 參數,可以讓計數只在特定的位上進行。
start 和 end 參數的設置和GETRANGE 命令類似,都可以使用負數值:比如 -1 表示最後一個位,而 -2表示倒數第二個位,以此類推。
不存在的 key 被當成是空字符串來處理,因此對一個不存在的 key 進行 BITCOUNT 操作,結果為 0 。
時間復雜度: O(N)
返回值: 被設置為 1 的位的數量。

127.0.0.1:6379[15]>  BITCOUNT bits
(integer) 0
127.0.0.1:6379[15]> SETBIT bits 0 1
(integer) 0
127.0.0.1:6379[15]>  BITCOUNT bits
(integer) 1
127.0.0.1:6379[15]>  SETBIT bits 3 1
(integer) 0
127.0.0.1:6379[15]> BITCOUNT bits
(integer) 2

模式:使用 bitmap 實現用戶上線次數統計
Bitmap 對於一些特定類型的計算非常有效。
假設現在我們希望記錄自己網站上的用戶的上線頻率,比如說,計算用戶 A 上線了多少天,用戶 B 上線了多少天,諸如此類,以此作為數據,從而決定讓哪些用戶參加 beta 測試等活動——這個模式可以使用SETBIT 和BITCOUNT 來實現。
比如說,每當用戶在某一天上線的時候,我們就使用SETBIT ,以用戶名作為 key ,將那天所代表的網站的上線日作為 offset 參數,並將這個 offset 上的為設置為 1 。
舉個例子,如果今天是網站上線的第 100 天,而用戶 peter 在今天閱覽過網站,那麼執行命令 SETBIT peter 100 1 ;如果明天 peter 也繼續閱覽網站,那麼執行命令 SETBIT peter 101 1 ,以此類推。
當要計算 peter 總共以來的上線次數時,就使用BITCOUNT 命令:執行 BITCOUNT peter ,得出的結果就是 peter 上線的總天數。
性能
前面的上線次數統計例子,即使運行 10 年,占用的空間也只是每個用戶 10*365 比特位 (bit),也即是每個用戶 456 字節。對於這種大小的數據來說,BITCOUNT 的處理速度就像GET 和INCR 這種 O(1) 復雜度的操作一樣快。
如果你的 bitmap 數據非常大,那麼可以考慮使用以下兩種方法:
  1. 將一個大的 bitmap 分散到不同的 key 中,作為小的 bitmap 來處理。使用 Lua 腳本可以很方便地完成這一工作。
  2. 使用BITCOUNT 的 start 和 end 參數,每次只對所需的部分位進行計算,將位的累積工作 (accumu-lating) 放到客戶端進行,並且對結果進行緩存 (caching)。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved