bitmap原理
通俗地说,就是用位置信息来记录真实的表达信息。用bitmap的一般使用场景–签到 来举例子的话。
假如一个班有8个同学,每个同学都有自己的学号1-8,就可以用8个bit来记录整个班的签到情况。
例如125,转换为二进制数就是 0111 1101
,然后我们就能知道学号2和8两个同学没来上课。
使用感悟
- 一般来说,只需要用到setbit、 getbit、 半个bitcount。
- setbit 就是 修改对应学号的bit、 getbit是获取对应学号的bit。 bitcount 是获取打卡的学生个数。
setbit key num val(0 or 1)
getbit key num
bitcount key
- 为什么说是半个bitcount呢,因为bitcount key 后面接的 start、end的单位是byte(8个bit),不是bit,往往容易误导人。比如说如果我想知道学号5-8的学生打卡情况,不是用‘bitcount sign 5 8’, 这个命令是用来获取学号41到64的学生打开情况的。
C++封装redis bitmap
bool SetBit(const std::string& key, const unsigned long offset, const int value)
{
bool flag = false;
int realValue = value ? 1 : 0;
redisReply *reply = (redisReply *)redisCommand(redisCon, "setbit %s %ld %d", key.c_str(), offset, realValue);
if (NULL == reply)
{
flag = false;
}
else if (reply->type != REDIS_REPLY_INTEGER)
{
flag = false;
freeReplyObject(reply);
}
else
{
flag = true;
freeReplyObject(reply);
}
return flag;
}
bool GetBit(const std::string& key, const unsigned long offset, int& value)
{
bool flag = false;
redisReply *reply = (redisReply *)redisCommand(redisCon, "getbit %s %ld", key.c_str(), offset);
if (NULL == reply)
{
flag = false;
}
else if (reply->type != REDIS_REPLY_INTEGER)
{
flag = false;
freeReplyObject(reply);
}
else
{
flag = true;
value = reply->integer;
freeReplyObject(reply);
}
return flag;
}
bool BitCount(const std::string& key, int& cnt)
{
if (!redisCon)
{
return false;
}
bool flag = false;
std::string cmd = "bitcount " + key;
redisReply *reply = (redisReply *)redisCommand(redisCon, "bitcount '%s'", key.c_str());
if (NULL == reply)
{
flag = false;
}
else if (reply->type != REDIS_REPLY_INTEGER)
{
flag = false;
freeReplyObject(reply);
}
else
{
flag = true;
cnt = reply->integer;
freeReplyObject(reply);
}
return flag;
}
注意事项
- redis的bitmap并没有做数据上的压缩优化,当偏移量比较大或数据量较小的时候,慎用bitmap。
- 你可能为了省空间而使用bitmap,使用场景不合适的话,可能会多用空间,甚至导致redis数据库空间不够,redis停止工作。
- 如果偏移量比较大,最好不要一个玩家一个bitmap。bitmap应该适用于一个大的整体。否则可能不如set。