Redis BitMapまとめ
4592 ワード
BitMapって何?
Bitmap(Bitset)Bitmapは連続する2進数(0または1)の列で、各ビットが位置する位置はオフセット(offset)であり、bitmapは最小単位bitで0または1の設定を行い、ある要素に対応する値または状態を表す.
RedisでのBitMap
Redisでは2.2.0バージョンから
setbit
、getbit
、bitcount
などいくつかの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