利用Redis BitMap 統計使用者活躍指標
阿新 • • 發佈:2019-02-02
bitMap原理 :
如下: index 從 0 到 9 ,依次對應到一個bit位上,如果index 代表使用者id,bit位上的0 1分表 代表使用者是否登入;
redis資料結構中 string 型別,包含了對bitmap的實現;在redis-cli中,可以通過setbit getbit 來對bit進行操作;本文通過jedis來對redis進行操作;
BitSet工具類:實現對通過jedis.get(key)取出的byte[]值與BitSet的轉換
具體對java中BitSet操作,見http://my.oschina.net/cloudcoder/blog/294810 ,該篇對bitSet用法介紹很詳細;
redis工具類:
1 統計系統中某天使用者登入的情況:以當天日期做為key ,比如 ‘20150410’ ,對應的 bitMap 的 index 用userId來標示,UserId這裡用 long 型表示,如果id不是以0開頭,可以加上相應的偏移量就OK了;如果該天使用者登入,呼叫activeUser方法,來更改bitMap相應index上的標示;
如果我們想統計該天使用者登入的數量,及登入的使用者id,可以通過如下方法實現:
//該天使用者總數
//該天登入所有的使用者id
2 如果我們想統計n天,連續登入的使用者數,及UserId:
如下: index 從 0 到 9 ,依次對應到一個bit位上,如果index 代表使用者id,bit位上的0 1分表 代表使用者是否登入;
-
1 0 1 1 0 1 1 0 1 1
- 0 1 2 3 4 5 6 7 8 9
redis資料結構中 string 型別,包含了對bitmap的實現;在redis-cli中,可以通過setbit getbit 來對bit進行操作;本文通過jedis來對redis進行操作;
BitSet工具類:實現對通過jedis.get(key)取出的byte[]值與BitSet的轉換
-
public class BitSetUtils {
-
/**
-
* 將BitSet物件轉化為ByteArray
-
* @param bitSet
-
* @return
-
*/
-
public static byte[] bitSet2ByteArray(BitSet bitSet) {
-
byte[] bytes = new byte[bitSet.size() / 8];
-
for (int i = 0; i < bitSet.size(); i++) {
-
int index = i / 8;
-
int offset = 7 - i % 8;
-
bytes[index] |= (bitSet.get(i) ? 1 : 0) << offset;
-
}
-
return bytes;
-
}
-
/**
-
*
-
* @param bytes
-
* @return
-
*/
-
public static BitSet byteArray2BitSet(byte[] bytes) {
-
BitSet bitSet = new BitSet(bytes.length * 8);
-
int index = 0;
-
for (int i = 0; i < bytes.length; i++) {
-
for (int j = 7; j >= 0; j--) {
-
bitSet.set(index++, (bytes[i] & (1 << j)) >> j == 1 ? true
-
: false);
-
}
-
}
-
return bitSet;
-
}
- }
具體對java中BitSet操作,見http://my.oschina.net/cloudcoder/blog/294810 ,該篇對bitSet用法介紹很詳細;
redis工具類:
-
public class RedisUtil {
-
static {
-
initPool();
-
}
-
private static volatile JedisPool jedisPool;
-
private static ResourceBundle resourceBundle;
-
public static Jedis getResource() {
-
return jedisPool.getResource();
-
}
-
public static void returnResource(Jedis jedis) {
-
jedisPool.returnResource(jedis);
-
}
-
public static void initPool() {
-
if(jedisPool != null){
-
return;
-
}
-
loadProperties();
-
String host = resourceBundle.getString("redis.host");
-
String passwd= resourceBundle.getString("redis.passwd");
-
int port = Integer.parseInt(resourceBundle.getString("redis.port"));
-
JedisPoolConfig config = config();
-
jedisPool = new JedisPool(config,host,port,60,passwd);
-
}
-
private static void loadProperties() {
-
resourceBundle = ResourceBundle.getBundle("config/redis-config");
-
}
-
private static JedisPoolConfig config() {
-
JedisPoolConfig config = new JedisPoolConfig();
-
return config;
-
}
-
public static void main(String[]args){
-
Jedis jedis= RedisUtil.getResource();
-
RedisUtil.returnResource(jedis);
-
}
- }
1 統計系統中某天使用者登入的情況:以當天日期做為key ,比如 ‘20150410’ ,對應的 bitMap 的 index 用userId來標示,UserId這裡用 long 型表示,如果id不是以0開頭,可以加上相應的偏移量就OK了;如果該天使用者登入,呼叫activeUser方法,來更改bitMap相應index上的標示;
-
public void activeUser(long userId, String dateKey) {
-
Jedis jedis= RedisUtil.getResource();
-
try{
-
jedis.setbit(dateKey,userId,true);
-
}finally {
-
RedisUtil.returnResource(jedis);
-
}
-
}
如果我們想統計該天使用者登入的數量,及登入的使用者id,可以通過如下方法實現:
//該天使用者總數
-
public long totalCount(String dateKey) {
-
Jedis jedis= RedisUtil.getResource();
-
try{
-
return jedis.bitcount(dateKey);
-
}finally {
-
RedisUtil.returnResource(jedis);
-
}
- }
//該天登入所有的使用者id
-
public List<Long> activeUserIds(String dateKey) {
-
Jedis jedis= RedisUtil.getResource();
-
try{
-
if(jedis.get(key)==null){
-
return null;
-
}
-
BitSet set= BitSetUtils.byteArray2BitSet(jedis.get(key).getBytes());
-
List<Long>list=new ArrayList<Long>();
-
for (long i=0;i<set.size();i++){
-
if(set.get(i)){
-
list.add(i);
-
}
-
}
-
return list;
-
}finally {
-
RedisUtil.returnResource(jedis);
-
}
- }
2 如果我們想統計n天,連續登入的使用者數,及UserId:
-
public List<Long> continueActiveUserCount(String... dateKeys) {
-
Jedis jedis= RedisUtil.getResource();
-
try{
-
BitSet all = null;
-
for (String key:dateKeys){
-
if(jedis.get(key)==null){
-
continue;
-
}
-
BitSet set= BitSetUtils.byteArray2BitSet(jedis.get(key).getBytes());
-
if(all==null){
-
all=set;
-
}
-
System.out.println(set.size());
-
all.and(set);
-
}
-
List<Long>list=new ArrayList<Long>();
-
for (long i=0;i<all.size();i++){
-
if(all.get(i)){
-
list.add(i);
-
}
-
}
-
return list;
-
}finally {
-
RedisUtil.returnResource(jedis);
-
}
- }