利用Redis BitMap 统计用户活跃指标

  bitMap原理 :

    如下: index 从 0 到 9 ,依次对应到一个bit位上,如果index 代表用户id,bit位上的0 1分表 代表用户是否登录;
  1. 1     0     1     1     0     1     1     0     1     1


  2. 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的转换

    
  1. public class BitSetUtils {

  2.     /**
  3.      * 将BitSet对象转化为ByteArray
  4.      * @param bitSet
  5.      * @return
  6.      */
  7.     public static byte[] bitSet2ByteArray(BitSet bitSet) {
  8.         byte[] bytes = new byte[bitSet.size() / 8];
  9.         for (int i = 0; i < bitSet.size(); i++) {
  10.             int index = i / 8;
  11.             int offset = 7 - i % 8;
  12.             bytes[index] |= (bitSet.get(i) ? 1 : 0) << offset;
  13.         }
  14.         return bytes;
  15.     }

  16.     /**
  17.      * 
  18.      * @param bytes
  19.      * @return
  20.      */
  21.     public static BitSet byteArray2BitSet(byte[] bytes) {
  22.         BitSet bitSet = new BitSet(bytes.length * 8);
  23.         int index = 0;
  24.         for (int i = 0; i < bytes.length; i++) {
  25.             for (int j = 7; j >= 0; j--) {
  26.                 bitSet.set(index++, (bytes[i] & (1 << j)) >> j == 1 ? true
  27.                         : false);
  28.             }
  29.         }
  30.         return bitSet;
  31.     }

  32. }
复制代码



    具体对java中BitSet操作,见 http://my.oschina.net/cloudcoder/blog/294810  ,该篇对bitSet用法介绍很详细;

redis工具类:

    
  1. public class RedisUtil {
  2.     static {
  3.         initPool();
  4.     }
  5.     private static volatile JedisPool jedisPool;
  6.     private static ResourceBundle resourceBundle;
  7.     public static Jedis getResource() {
  8.         return jedisPool.getResource();
  9.     }
  10.     public static void returnResource(Jedis jedis) {
  11.         jedisPool.returnResource(jedis);
  12.     }
  13.     public static void initPool() {
  14.             if(jedisPool != null){
  15.                 return;
  16.             }
  17.             loadProperties();
  18.             String host = resourceBundle.getString("redis.host");
  19.             String passwd= resourceBundle.getString("redis.passwd");
  20.             int port = Integer.parseInt(resourceBundle.getString("redis.port"));
  21.             JedisPoolConfig config = config();
  22.             jedisPool = new JedisPool(config,host,port,60,passwd);
  23.     }
  24.     private static void loadProperties() {
  25.         resourceBundle = ResourceBundle.getBundle("config/redis-config");
  26.     }
  27.     private static JedisPoolConfig config() {
  28.         JedisPoolConfig config = new JedisPoolConfig();
  29.         return config;
  30.     }
  31.     public static void main(String[]args){
  32.        Jedis jedis= RedisUtil.getResource();
  33.        RedisUtil.returnResource(jedis);
  34.     }
  35. }
复制代码



1 统计系统中某天用户登录的情况:以当天日期做为key ,比如 ‘20150410’ ,对应的 bitMap 的 index 用userId来标示,UserId这里用  long 型表示,如果id不是以0开头,可以加上相应的偏移量就OK了;如果该天用户登录,调用activeUser方法,来更改bitMap相应index上的标示;

    
  1. public void activeUser(long userId, String dateKey) {
  2.     Jedis jedis= RedisUtil.getResource();
  3.     try{
  4.         jedis.setbit(dateKey,userId,true);
  5.     }finally {
  6.         RedisUtil.returnResource(jedis);
  7.     }
  8. }
复制代码


如果我们想统计该天用户登录的数量,及登录的用户id,可以通过如下方法实现:

    
//该天用户总数
  1. public long totalCount(String dateKey) {
  2.     Jedis jedis= RedisUtil.getResource();
  3.     try{
  4.         return jedis.bitcount(dateKey);
  5.     }finally {
  6.         RedisUtil.returnResource(jedis);
  7.     }
  8. }
复制代码



//该天登录所有的用户id
  1. public List<Long> activeUserIds(String  dateKey) {
  2.     Jedis jedis= RedisUtil.getResource();
  3.     try{
  4.          
  5.         if(jedis.get(key)==null){
  6.                  return null;
  7.          }
  8.         BitSet set= BitSetUtils.byteArray2BitSet(jedis.get(key).getBytes());
  9.        
  10.         List<Long>list=new ArrayList<Long>();
  11.         for (long i=0;i<set.size();i++){
  12.             if(set.get(i)){
  13.                 list.add(i);
  14.             }
  15.         }
  16.         return list;
  17.     }finally {
  18.         RedisUtil.returnResource(jedis);
  19.     }
  20. }
复制代码



   2 如果我们想统计n天,连续登录的用户数,及UserId:

    
  1. public List<Long> continueActiveUserCount(String... dateKeys) {
  2.     Jedis jedis= RedisUtil.getResource();
  3.     try{
  4.         BitSet all = null;
  5.         for (String key:dateKeys){
  6.              if(jedis.get(key)==null){
  7.                  continue;
  8.              }
  9.              BitSet set= BitSetUtils.byteArray2BitSet(jedis.get(key).getBytes());
  10.              if(all==null){
  11.                  all=set;
  12.              }
  13.              System.out.println(set.size());
  14.              all.and(set);
  15.         }
  16.         List<Long>list=new ArrayList<Long>();
  17.         for (long i=0;i<all.size();i++){
  18.             if(all.get(i)){
  19.                 list.add(i);
  20.             }
  21.         }
  22.         return list;
  23.     }finally {
  24.         RedisUtil.returnResource(jedis);
  25.     }
  26. }
复制代码

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值