Redis BitMapまとめ

4592 ワード

BitMapって何?


Bitmap(Bitset)Bitmapは連続する2進数(0または1)の列で、各ビットが位置する位置はオフセット(offset)であり、bitmapは最小単位bitで0または1の設定を行い、ある要素に対応する値または状態を表す.

RedisでのBitMap


Redisでは2.2.0バージョンからsetbitgetbitbitcountなどいくつかのbitmap関連コマンドが追加されました.新しいコマンドですが、新しいデータ型は追加されていません.setbitなどのコマンドはsetでの拡張にすぎないからです.bitmapではAND,OR,XORおよび他のビット操作を実行できます.

関連コマンド


setBit

説明:指定したkeyのoffsetビットにvalueを割り当てます.
パラメータ:[key,offset,value]:bool or int(1 or 0)
戻り値:LONG:0 or 1
getBit

説明:指定したkeyのバイナリ情報を返します.
パラメータ:[key,offset]
戻り値:LONG
bitCount

説明:指定したkeyのビットの値が1の個数を返します.
パラメータ:[key,start,offset](byte単位でbitではありません)
戻り値:LONG
bitOp

説明:異なるバイナリ格納データに対するビット演算(AND、OR、NOT、XOR)
パラメータ:operation destkey key[key...]
戻り値:LONG
 

bitmapの利点、制限


メリット
1.最小の単位bitに基づいて格納するので、非常に省スペースです.  2.設定時時間複雑度O(1)、読み出し時時間複雑度O(n)は、非常に高速である.  3.バイナリデータの格納は,関連計算を行う際に非常に速い.  4.便利な拡張
制限
redisではbitマッピングは512 MB以内に制限されているので,最大2^32ビットである.各keyのビット数を制御することを推奨します.読み取り時の時間複雑度O(n)のため、大きいシリアル読み取りほど時間がかかります.

bitmap空間、時間大まか計算方式


1台の2010 MacBook Proでは、offsetは2^32-1(512 MBの割り当て)で~300 ms、offsetは2^30-1(128 MBの割り当て)で~80 ms、offsetは2^28-1(32 MBの割り当て)で~30 ms、offsetは2^26-1(8 MBの割り当て)で8 ms必要です.
大体の空間占有計算式は:($offset/8/1024/1024)MB
 

シーンの操作


簡単な例:日アクティブユーザー
今日ログインしたユーザー数を統計するために、bitmapを作成し、各ユーザーIDを識別します.あるユーザーが私たちのページにアクセスしたり、操作を実行したりすると、bitmapでこのユーザーを識別する位置を1にします.このbitmapをRedisで取得するキー値は、ユーザが操作を行うタイプとタイムスタンプによって取得される. 
1011 1101
0010 0101
 
この簡単な例では、ユーザがログインするたびにredisが実行する.setbit(daily_active_users, user_id, 1).bitmapにおける対応する位置を1とし,時間的複雑度をO(1)とする.統計bitmapの結果、今日9人のユーザーがログインしていることがわかりました.Bitmapのkeyはdaily_active_users、その値は1011110100100101です.
私は以前から前から15-8|7-0だと思っていましたが、バイトと同じように、後ろから0-7|8-15の順番であることがわかりました.
127.0.0.1:6379> set daily_active_users "\x00\x00"
OK

127.0.0.1:6379> get daily_active_users
"\x00\x00"

127.0.0.1:6379> setbit daily_active_users 0 1
(integer) 0

127.0.0.1:6379> get daily_active_users
"\x80\x00"

127.0.0.1:6379> setbit daily_active_users 14  1
(integer) 0
127.0.0.1:6379> get daily_active_users
"\x80\x02"

ユーザー署名
 
多くのサイトでは署名機能が提供されています(ここではデータの到着を考慮しません)、最近の1ヶ月の署名状況を示す必要があります.bitmapを使用するとどうすればいいですか?一言でコードが合わない! 
connect('127.0.0.1');


//  uid
$uid = 1;

//   uid key
$cacheKey = sprintf("sign_%d", $uid);

//          
$startDate = '2017-01-01';

//     
$todayDate = '2017-01-21';

//  offset
$startTime = strtotime($startDate);
$todayTime = strtotime($todayDate);
$offset = floor(($todayTime - $startTime) / 86400);

echo "    {$offset} " . PHP_EOL;

//  
//              ?  365/8=45.625   ,  ,      ?
$redis->setBit($cacheKey, $offset, 1);

//      
$bitStatus = $redis->getBit($cacheKey, $offset);
echo 1 == $bitStatus ? '       ' : '      ';
echo PHP_EOL;

//       
echo $redis->bitCount($cacheKey) . PHP_EOL;

/**
*             
*     ,bitCount     start end  ,             ,     " "   
*           get   value   ,    。    value    ,              45   
*             ,  30 ,      1.31KB(      ?)
*/
//          
echo $redis->bitCount($cacheKey, 0, 20) . PHP_EOL;

アクティブなユーザー統計
$key1 = 'Userlogin2017-08-01';
$key2 = 'Userlogin2017-08-02';
$key3 = 'Userlogin2017-08-03';

##      8 1     8 2       

$redis->setBit($key1, $uid, 1);
$redis->setBit($key2, $uid, 1);

##  bitmap     1 2       

$redis->bitOp('AND','8182',$key1,$key2);
$both_active = $redis->bitCount('8182');

##  bitmap     1    2    3       

$redis->bitOp('OR','818283',$key1,$key2,$key3);
$other_active = $redis->bitCount('818283');

現在のサイトに5000 Wユーザーがいると仮定すると、1日のデータは約5000000/8/1024/1024=6 MB

使用時:


  アクティブなユーザーが百万レベルであれば、Redis BitMapを使うのがお得です.
  アクティブユーザが少ない場合,ユーザidはいずれも10ビット以上のintである.それはメモリがもったいないので、setコレクションを使って交差を求めればいいのです.
参照先:
https://segmentfault.com/a/1190000008188655
https://blog.csdn.net/u011957758/article/details/74783347
https://blog.csdn.net/qq_28018283/article/details/76572342