redis位圖

<?php

function frstr($str){
    return str_pad($str,8,'0',STR_PAD_LEFT);
}


$php='';
$p= frstr(decbin(ord('p')));

$h= frstr(decbin(ord('h')));

$php=$p.$h.$p;

echo $php;
echo PHP_EOL;

$len=strlen($php);
$index=[];
for($i=0;$i<$len;$i++){
    if($php[$i]==1){
        $index[]=$i;
    }
}
print_r($index);
01110000,01101000,01110000
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 9
    [4] => 10
    [5] => 12
    [6] => 17
    [7] => 18
    [8] => 19
)

01110000,01101000,01110000php

1,2,3,9,10,12,17,18,19 共9位需設置爲1數組

127.0.0.1:0>get p
null

127.0.0.1:0>setbit p 1 1
"0"

127.0.0.1:0>setbit p 2 1
"0"

127.0.0.1:0>setbit p 3 1
"0"

127.0.0.1:0>get p
"p"

127.0.0.1:0>setbit p 9 1
"0"

127.0.0.1:0>setbit p 10 1
"0"

127.0.0.1:0>setbit p 12 1
"0"

127.0.0.1:0>setbit p 17 1
"0"

127.0.0.1:0>setbit p 18 1
"0"

127.0.0.1:0>setbit p 19 1
"0"

127.0.0.1:0>get p
"php"

統計和查找

Redis 提供了位圖統計指令 bitcount 和位圖查找指令 bitposcode

  • bitcount 用來統計指定位置範圍內 1 的個數
  • bitpos 用來查找指定範圍內出現的第一個 0 或 1

    bitcount,bitpos

127.0.0.1:0>bitcount p
"9"
127.0.0.1:0>bitcount p 0 0  #第一個字符中1的個數
"3"
127.0.0.1:0>bitcount p 0 1  #前2個字符中1的個數
"6"
127.0.0.1:0>bitpos p 0     #第一個0位
"0"

127.0.0.1:0>bitpos p 1      #第一個1位
"1"

127.0.0.1:0>bitpos p 1 1 1  #從第二個字符算起第一個1位
"9"

127.0.0.1:0>bitpos p 1 2 2  # 從第三個字符算起,第一個 1 位
"17"

bitfield

bitfield(3.2版本以後) 有三個子指令,分別是 get/set/incrby,它們均可以對指定位片斷進行讀寫,可是最多隻能處理 64 個連續的位,若是超過 64 位,就得使用多個子指令,bitfield 能夠一次執行多個子指令ci

php
get

01110000,01101000,01110000it

127.0.0.1:6379> get p
"php"
127.0.0.1:6379> bitfield p get u4 0  # 從第0個位開始取4個位  即爲 0111  結果是無符號數 (u)
1) (integer) 7
127.0.0.1:6379> bitfield p get u3 2  #從第2個位開始取3個位   即爲110       結果是無符號數 (u)
1) (integer) 6
127.0.0.1:6379> bitfield p get i4 0  #從第0個位開始取4個位   即爲0111      結果是有符號數 (i)
1) (integer) 7
127.0.0.1:6379> bitfield p get i3 2   #從第2個位開始取3個    即爲110      結果是有符號數 (i)
1) (integer) -2
127.0.0.1:6379> bitfield p  get u4 0  get u3 2  get i4 0     get i3 2
1) (integer) 7
2) (integer) 6
3) (integer) 7
4) (integer) -2

所謂有符號數是指獲取的位數組中第一個位是符號位,剩下的纔是值
若是第一位是 1,那就是負數
無符號數表示非負數,沒有符號位,獲取的位數組所有都是值。有符號數最多能夠獲取 64 位,無符號數只能獲取 63 位 (由於 Redis 協議中的 integer 是有符號數,最大 64 位,不能傳遞 64 位無符號值)
若是超出位數限制,Redis 就會告訴你參數錯誤io

01110000,01101000,01110000
把第二個h這隻爲p
只須要把第11位由0->1,第12位由1->0便可
setbit p 11 1
setbit p 12 0
127.0.0.1:6379> setbit p 11 1
(integer) 0
127.0.0.1:6379> setbit p 12 0
(integer) 1
127.0.0.1:6379> get p
"ppp"

127.0.0.1:6379> set p php
OK
127.0.0.1:6379> bitfield p set u8 8 97  #從第 8 個位開始,將接下來的 8 個位用無符號數 97 替換
1) (integer) 104
127.0.0.1:6379> get p
"pap"

incrby

它用來對指定範圍的位進行自增操做自增有可能出現溢出
若是增長了正數,會出現上溢,若是增長的是負數,就會出現下溢出function

Redis 默認的處理是折返。若是出現了溢出,就將溢出的符號位丟掉
若是是 8 位無符號數 255,加 1 後就會溢出,會所有變零。若是是 8 位有符號數 127,加 1 後就會溢出變成 -128class

bitfield p incrby u7 1 1

127.0.0.1:6379> set p php
OK
127.0.0.1:6379> bitfield p incrby u7 1 1  # 從第7位開始,對接下來的1位無符號數 +1
1) (integer) 113
127.0.0.1:6379> get p
"qhp"
127.0.0.1:6379> bitfield p incrby u7 1 1
1) (integer) 114       #r 的ascii碼 爲114
127.0.0.1:6379> get p
"rhp"
127.0.0.1:6379> set  p php
OK
127.0.0.1:6379> bitfield p incrby u1 1 1
1) (integer) 0
127.0.0.1:6379> get p
"0hp"
127.0.0.1:6379> bitfield p incrby u1 1 1
1) (integer) 1
127.0.0.1:6379> get p
"php"

bitfield 指令提供了溢出策略子指令

overflow,用戶能夠選擇溢出行爲,默認是折返 (wrap),還能夠選擇失敗 (fail) 報錯不執行,以及飽和截斷 (sat),超過了範圍就停留在最大最小值
overflow 指令隻影響接下來的第一條指令,這條指令執行完後溢出策略會變成默認值折返 (wrap)二進制

飽和截斷 SAT

p的二進制

0111 0000

127.0.0.1:6379> get p
"p"
127.0.0.1:6379> bitfield p overflow sat incrby u4 1 1
1) (integer) 15
127.0.0.1:6379> get p
"x"
127.0.0.1:6379> bitfield p overflow sat incrby u4 1 1
1) (integer) 15
127.0.0.1:6379> get p
"x"
127.0.0.1:6379> bitfield p overflow sat incrby u4 1 1 ## 保持最大值
1) (integer) 15
127.0.0.1:6379> get p
"x"


0111 0000


執行

bitfield p overflow sat incrby u4 1 1
後變爲

0111 1000


繼續

bitfield p overflow sat incrby u4 1 1

由於採起了截斷 (sat),超過了範圍就停留在最大最小值

失敗不執行 FAIL SAT

127.0.0.1:6379> set p p
OK
127.0.0.1:6379> bitfield p overflow fail incrby u5 1 1
1) (integer) 29
127.0.0.1:6379> get p
"t"
127.0.0.1:6379> bitfield p overflow fail incrby u5 1 1
1) (integer) 30
127.0.0.1:6379> get p
"x"
127.0.0.1:6379> bitfield p overflow fail incrby u5 1 1
1) (integer) 31
127.0.0.1:6379> get p
"|"
127.0.0.1:6379> bitfield p overflow fail incrby u5 1 1
1) (nil)
127.0.0.1:6379> get p
"|"
127.0.0.1:6379>

過程分析

0111 0000


執行

bitfield p overflow fail incrby u5 1 1
變爲

0111 0100

ascii碼爲116 即爲字符t

而後繼續執行

bitfield p overflow fail incrby u5 1 1

0111 1000

ascii爲120即爲字符 x

而後繼續執行

bitfield p overflow fail incrby u5 1 1
變爲

0111 1100

ascii 124即爲字符 |

再繼續執行就會溢出,因此保留當前的最大值

相關文章
相關標籤/搜索