In Redis verwenden wir oft set, get und andere Befehle. Wenn Sie vorsichtig sind, ist Ihnen aufgefallen, dass es mehrere ähnliche Befehle namens setbit und getbit gibt.
Es verwendet ein Bit, um den Wert oder Status eines Elements darzustellen, und der Schlüssel ist das entsprechende Element selbst. Wir wissen, dass 8 Bits ein Byte bilden können, sodass die Bitmap selbst erheblich Speicherplatz spart.
Redis hat seit Version 2.2.0 mehrere Bitmap-bezogene Befehle wie setbit
, getbit
, bitcount
usw. hinzugefügt. Obwohl es sich um einen neuen Befehl handelt, wird kein neuer Datentyp hinzugefügt, da Befehle wie setbit
nur Erweiterungen von set
sind.
BefehlSETBIT key offset value
KomplexitätO(1)
Setzen oder löschen Sie den Bitwert (String) des Schlüssels am Offset (nur 0 oder 1).
Auf einem 2010 MacBook Pro beträgt der Offset 2^32-1 (512 MB zugewiesen) und dauert ca. 300 ms Offset ist 2^ 30-1 (zugewiesen 128 MB) dauert ~80 ms, Offset 2^28-1 (zugewiesen 32 MB) dauert ~30 ms, Offset 2^26-1 (zugewiesen 8 MB) dauert 8 ms.
Die ungefähre Formel zur Berechnung der Raumbelegung lautet: ($offset/8/1024/1024)MB
Viele Websites bieten Anmeldefunktionen (nicht berücksichtigt). hier) Datenimplementierung ist wichtig) und muss den Check-in-Status im letzten Monat anzeigen. Was sollen wir tun, wenn Bitmap verwendet wird? Der Code wird in einem Wort offenbart!
<?php $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;
Zeit als Cache-Schlüssel verwenden und dann die Benutzer-ID verschieben. Wenn sie an diesem Tag aktiv ist, setzen Sie sie auf 1
Dann Wie soll ich eine bestimmte Anzahl von Tagen/Monaten/Jahren berechnen, die aktive Benutzer haben (vorläufig vereinbart, nur ein Tag online während des statistischen Zeitraums wird als aktiv bezeichnet), führen Sie bitte einen Redis-Befehl aus
Befehl BITOP operation destkey key [key ...]
Erklärung: Für eine oder mehrere Bitoperationen an einem Zeichenfolgenschlüssel ausführen, der Binärbits enthält, und das Ergebnis im Zielschlüssel speichern.
Hinweis: Der BITOP-Befehl unterstützt alle Parameter der vier Operationen AND, OR, NOT und /1024/1024=6MB
//日期对应的活跃用户 $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;
Tatsächlich kann BitMap in vielen Szenarien verwendet werden (natürlich unterliegt es einigen Einschränkungen) und Ideen können sich weiterhin verbreiten~ Freunde können mir gerne eine Nachricht zur Diskussion hinterlassen~
//批量设置在线状态 $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,然后自己计算 * 具体计算方法改天再写吧,之前写的代码找不见了。。。 */
In Redis verwenden wir häufig Befehle wie set und get. Wenn Sie vorsichtig sind, ist Ihnen aufgefallen, dass es mehrere ähnliche Befehle namens setbit und getbit gibt.
Was ist BitMap?
stellt den Wert oder Status eines Elements durch ein Bit dar, und der Schlüssel ist das entsprechende Element selbst. Wir wissen, dass 8 Bits ein Byte bilden können, sodass die Bitmap selbst erheblich Speicherplatz spart. BitMap in RedisRedis hat seit Version 2.2.0 mehrere Bitmap-bezogene Befehle wie usw. hinzugefügt. Obwohl es sich um einen neuen Befehl handelt, wird kein neuer Datentyp hinzugefügt, da Befehle wie setbit
nur Erweiterungen von getbit
sind. bitcount
setbit
Einführung in den Setbit-Befehlset
SETBIT key offset value
Setzen oder löschen Sie den Bitwert (String) des Schlüssels am Offset (nur 0 oder 1). O(1)
Speicherplatzbelegung und die Zeit, die zum erstmaligen Zuweisen von Speicherplatz benötigt wird
Nutzungsszenario 1: Benutzeranmeldung($offset/8/1024/1024)MB
<?php $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;
Zeit als Cache-Schlüssel verwenden, und dann wird die Benutzer-ID versetzt. Wenn sie an diesem Tag aktiv ist, setzen Sie sie auf 1
Wie soll ich dann? Bestimmte Tage berechnen/ Was die aktiven Benutzer im Monat/Jahr betrifft (vorerst wird vereinbart, dass nur ein Tag online innerhalb des statistischen Zeitraums als aktiv bezeichnet wird), verwenden Sie bitte den nächsten Redis-Befehl
Befehl BITOP operation destkey key [key ...]
Beschreibung: Speichern Sie eine oder mehrere Binärdateien. Führen Sie Bitoperationen am Bitstring-Schlüssel durch und speichern Sie das Ergebnis im Zielschlüssel.
Hinweis: Der BITOP-Befehl unterstützt alle Parameter der vier Operationen AND, OR, NOT und /1024/1024=6MB
//日期对应的活跃用户 $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;
Tatsächlich kann BitMap in vielen Szenarien verwendet werden (natürlich unterliegt es einigen Einschränkungen) und Ideen können sich weiterhin verbreiten~ Freunde können mir gerne eine Nachricht zur Diskussion hinterlassen~
//批量设置在线状态 $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,然后自己计算 * 具体计算方法改天再写吧,之前写的代码找不见了。。。 */