利用Redis BitMap 統計用戶活躍指標

    bitMap原理 :java

    以下: index 從 0 到 9 ,依次對應到一個bit位上,若是index 表明用戶id,bit位上的0 1分表 表明用戶是否登陸;redis

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用法介紹很詳細;spa

redis工具類:.net

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上的標示;
code

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:
blog

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);
    }
}

 


轉載請註明來源:http://my.oschina.net/robinyao/blog/398808get

相關文章
相關標籤/搜索