In the process of development, we may encounter user registration, statistics on the day of active users, as well as each user's online status development needs, we may use the traditional method, according to the corresponding requirements of the design of database tables, such as the cost of large storage space, and performance is not too good, the following will introduce you simple, The method used.
Before introducing the implementation method, we will introduce a key word ' bitmap ' in Redis.
What is bitmap?
is to represent the value or state of an element by a bit, where the key is the corresponding element itself. We know that 8 bits can form a byte, so the bitmap itself will save a lot of storage space.
Bitmap in Redis
Redis has added several bitmap-related commands, such as Setbit,getbit,bitcount, starting with version 2.2.0. Although it is a new command, there is no new data type, because the Setbit command is just an extension on set.
Setbit Command Introduction
Directive setbit key offset value
Complexity O (1)
Sets or empties the value of the key (string) at offset by a bit (only 0 or 1).
Space occupancy, and the time required for the first allocation of space
On a 2010MacBook pro, offset is 2^32-1 (assigning 512MB) requires ~300ms,offset for 2^30-1 (assigning 128MB) requires ~80ms,offset for 2^28-1 (assigning 32MB) requires ~30ms, Offset for 2^26-1 (allocated 8MB) requires 8ms. < from official documents >
Approximate space occupancy Calculation formula is:($offset/8/1024/1024) MB
Use scenario One: User Sign in
Many websites provide the check-in function (this does not take into account the data landing), and need to show the last one months of check-in, if using bitmap what do we do? A word not bright code!
<?php$redis = new Redis (); $redis->connect (' 127.0.0.1 ');//user Uid$uid = 1;/ /record with UID Key$cachekey = sprintf ("sign_%d", $uid);//start with check-in function date $startdate = ' 2017-01-01 ';//today's date $todaydate = ' 2017-01-21 ';//Calculation Offset$starttime = Strtotime ($startDate); $todayTime = Strtotime ($todayDate); $offset = Floor (($ todaytime-$startTime)/86400); echo "Today is {$offset} days". php_eol;//Registration//How much space will a user occupy in a year? About 365/8 = 45.625 bytes, good small, have the wood been stunned? $redis->setbit ($cacheKey, $offset, 1);//check-in Status $bitstatus = $redis->getbit ($cacheKey, $offset); echo 1 = = $ Bitstatus? ' Sign in today ': ' Not yet checked in '; Echo php_eol;//calculates the total number of sign-in echoes $redis->bitcount ($cacheKey). php_eol;/*** Calculate the number of check-in times during a certain period of time * Unfortunately, Bitcount provides the start and end arguments, but this is the position of the string, not the position of the corresponding "bit." Fortunately, we can get the value out of our own parse by the take command. And this value is not too large, the above calculated a user only 45 bytes a year * to our site to set a small target, run 30 years, then a total of 1.31KB (ask you dick not dick?) *///This is a wrong way to calculate echo $redis->bitcount ($cacheKey, 0, 20). Php_eol;
Use Scenario two: Count Active users
Use time as CacheKey, then the user ID is offset and set to 1 if active today
Then I should calculate a certain days/months/years of active users (for the time being, only one day in the statistics is called active), please call the next Redis command
Command bitop operation Destkey key [key ...]
Description: A bit operation is performed on one or more string keys that hold bits, and the result is saved to Destkey.
Description: The Bitop command supports any of the four operations of the and, or, not, XOR
//a date corresponding to the active user $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 (on);//Bulk Set Active state 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;//Total Active Users: 6 echo "Total Active Users:". $redis->bitcount (' stat '). Php_eol, $redis->bitop (' and ', ' stat1 ', ' stat_2017-01-10 ', ' stat_2017-01-11 ', ' stat_2017-01-14 '). Php_eol;//Total Active Users: 2 echo "Total Active Users:". $redis->bitcount (' STAT1 '). Php_eol, $redis->bitop (' and ', ' stat2 ', ' stat_2017-01-10 ', ' stat_2017-01-11 '). Php_eol;//Total Active Users: 8 echo "Total Active Users:". $redis->bitcount (' Stat2 '). Php_eol;
Use scenario Three: User Online status
A time ago to develop a project, the other side provided me with a query whether the current user is online interface. Do not understand how the other side is to do, oneself consider a bit, use bitmap is a space efficiency and high of a method, only need a key, then the user ID is offset, if the line is set to 1, not the line is set to 0, and the above scene, 5000W users only need 6MB of space.
Bulk Set Online Status $uids = Range (1, 500000), foreach ($uids as $uid) {$redis->setbit (' online ', $uid, $uid% 2);}//One get status $ UIDs = range (1, 500000), $startTime = Microtime (True), foreach ($uids as $uid) {echo $redis->getbit (' online ', $uid). P Hp_eol;} $endTime = Microtime (TRUE);//On my Computer, it takes 25 seconds for the status of 50W users to echo "total:". ($endTime-$startTime).
"S";/** * for batch acquisition, above is a low-efficiency approach, can actually get to value through get, and then calculate the calculation method of the * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ... */
In fact, bitmap can use a lot of scenes (of course, will be subject to some restrictions), thinking can continue to spread ~ Welcome to my small friends to discuss the message ~