redisのbitmap使用シーン
32327 ワード
BitMapって何?
ある要素に対応する値または状態をbitビットで表し、keyは対応する要素自体である.8 bitで1 Byteを構成できることを知っていますので、bitmap自体はストレージスペースを大幅に節約します.
RedisでのBitMap
Redisは2.2.0バージョンからsetbit,getbit,bitcountなどいくつかのbitmap関連コマンドを追加した.新しいコマンドですが、新しいデータ型は追加されていません.setbitなどのコマンドはset上の拡張にすぎません.
setbitコマンドの説明
命令SETBIT key offset value複雑度O(1)keyのvalue(文字列)offsetでのbit値を設定またはクリアする(0または1のみ).
空間占有、及び第1回の空間割り当てに要する時間は、1台の2010 MacBook Proでoffsetは232-1(割り当て512 MB)で〜300 ms、offsetは230-1(割り当て128 MB)で〜80 ms、offsetは228-1(割り当て32 MB)で〜30 ms、offsetは226-1(割り当て8 MB)で8 ms必要である.大体の空間占有計算式は:($offset/8/1024/1024)MB
使用シーン1:ユーザーの活躍
1週間のユーザーログイン状況
127.0.0.1:6379> setbit Monday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Monday 8298191 1
(integer) 0
127.0.0.1:6379> setbit Monday 8892198 1
(integer) 0
127.0.0.1:6379> setbit Tuesday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Tuesday 8298191 0
(integer) 0
127.0.0.1:6379> setbit Tuesday 8892198 1
(integer) 0
127.0.0.1:6379> setbit Wednesday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Wednesday 8298191 1
(integer) 0
127.0.0.1:6379> setbit Wednesday 8892198 1
(integer) 0
127.0.0.1:6379> setbit Thursday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Thursday 8298191 0
(integer) 0
127.0.0.1:6379> setbit Thursday 8892198 0
(integer) 0
127.0.0.1:6379> setbit Friday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Friday 8298191 1
(integer) 0
127.0.0.1:6379> setbit Friday 8892198 1
(integer) 0
127.0.0.1:6379> setbit Saturday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Saturday 8298191 1
(integer) 0
127.0.0.1:6379> setbit Saturday 8892198 0
(integer) 0
127.0.0.1:6379> setbit Sunday 8987129 0
(integer) 0
127.0.0.1:6379> setbit Sunday 8298191 1
(integer) 0
127.0.0.1:6379> setbit Sunday 8892198 0
(integer) 0
次に、7日間のログイン行動を持つユーザーを計算するには、月曜日から金曜日までの値をビットまたは演算するだけで、下位と演算子を補充できます.
(&)
, “ ” 。
:0&0=0; 0&1=0; 1&0=0; 1&1=1;
: “1”, “1”, 0
(|)
, “ ” 。
:0|0=0; 0|1=1; 1|0=1; 1|1=1;
: 1, 1。
(^)
, “ ” 。
:0^0=0; 0^1=1; 1^0=1; 1^1=0;
: , “ ”( ), 1, 0。
bitop operation rs key 1[key 2...]key 1 key 2をoperationし、結果をrsに保存operationはAND(AND)OR(または)NOT(非)XOR(イソ)であってもよい
最終計算7日以内にログインしたアクティブユーザー:
127.0.0.1:6379> bitop OR result Monday Tuesday Wednesday Thursday Friday Saturday Sunday
8298191 1|0|1|0|1|1|1|1=1 8892198 1|1|1|0|1|0|0=1 8987129 0|0|0|0|0|0|0|0|0|0|0|0|0=0ここで計算した結果、3つのuidが連続していると仮定すると110になりますが、実際の記憶位置は...1...1...0...つまり今週、2人のアクティブなユーザーがログインしたことがあります.使用シーン2:アクティブなユーザーの統計
使用時間をcacheKeyとし、ユーザーIDをoffsetとし、当日アクティブになったら1に設定します.では、ある日/月/年のアクティブユーザーを計算するとします(一応、統計時間内にオンラインがある日だけアクティブと呼ばれます)、次のredisのコマンドコマンドコマンドコマンドコマンドBITOP operation destkey[key...]説明:バイナリビットを保存する文字列keyを1つ以上ビット操作し、結果をdestkeyに保存します.説明:BITOPコマンドはAND、OR、NOT、XORの4種類の操作のいずれかのパラメータをサポートする
//
$data = array(
'2017-01-10' => array(1,2,3,4,5,6,7,8,9,10),
'2017-01-11' => array(1,2,3,4,5,6,7,8),
'2017-01-12' => array(1,2,3,4,5,6),
'2017-01-13' => array(1,2,3,4),
'2017-01-14' => array(1,2)
);
//
foreach($data as $date=>$uids) {
$cacheKey = sprintf("stat_%s", $date);
foreach($uids as $uid) {
$redis->setBit($cacheKey, $uid, 1);
}
}
$redis->bitOp('AND', 'stat', 'stat_2017-01-10', 'stat_2017-01-11', 'stat_2017-01-12') . PHP_EOL;
// :6
echo " :" . $redis->bitCount('stat') . PHP_EOL;
$redis->bitOp('AND', 'stat1', 'stat_2017-01-10', 'stat_2017-01-11', 'stat_2017-01-14') . PHP_EOL;
// :2
echo " :" . $redis->bitCount('stat1') . PHP_EOL;
$redis->bitOp('AND', 'stat2', 'stat_2017-01-10', 'stat_2017-01-11') . PHP_EOL;
// :8
echo " :" . $redis->bitCount('stat2') . PHP_EOL;
現在のサイトに5000 Wユーザーがいると仮定すると、1日のデータは約5000000/8/1024/1024=6 MB
使用シーン3:ユーザーのオンライン状態
この間、現在のユーザーがオンラインであるかどうかを問い合わせるインタフェースを提供してくれたプロジェクトを開発しました.相手がどのようにしているのか分からず、自分で考えてみましたが、bitmapを使うのは省スペースで効率的な方法で、keyが1つしか必要なく、ユーザーIDがoffsetで、オンラインであれば1に設定し、オンラインでなければ0に設定し、上記のシーンと同じように5000 Wユーザーは6 MBのスペースしか必要ありません.
//
$uids = range(1, 500000);
foreach($uids as $uid) {
$redis->setBit('online', $uid, $uid % 2);
}
//
$uids = range(1, 500000);
$startTime = microtime(true);
foreach($uids as $uid) {
echo $redis->getBit('online', $uid) . PHP_EOL;
}
$endTime = microtime(true);
// , 50W 25
echo "total:" . ($endTime - $startTime) . "s";
/**
* , , get value,
* , 。。。
*/
使用シーン4:ユーザー署名
多くのサイトでは署名機能が提供されています(ここではデータの到着を考慮しません)、最近の1ヶ月の署名状況を示す必要があります.bitmapを使用するとどうすればいいですか?一言でコードが合わない!
$redis = new Redis();
$redis->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;