redis高级数据类型有两个
独立总数:一个人一天访问一个网站多次,算一个访客(UA),即统计的时候需要去重。
占据空间虽小,但是不精确
适合统计用户签到,0-1问题
比如第一位的01 表示今年第一天到没到。第二位的 01 表示今年第二天到没到。第365位表示第365天到没到。这样是连续的。
这两种都适合用于对网站的运营数据进行统计。且统计的时候非常节约内存,效率高。
这两种机制 以及适用场景都不一样,本节先处理其语法问题。
在RedisTests中
演示hyperLogLog
// 统计20万个重复数据的独立总数(独立总数即去重以后的数据个数).
@Test
public void testHyperLogLog() {
String redisKey = "test:hll:01";//hll是HyperLogLog缩写
for (int i = 1; i <= 100000; i++) {
redisTemplate.opsForHyperLogLog().add(redisKey, i);
}//生成十万个不重复数据
for (int i = 1; i <= 100000; i++) {
int r = (int) (Math.random() * 100000 + 1);//r为1-十万之间的整数
redisTemplate.opsForHyperLogLog().add(redisKey, r);
}//生成十万个不重复数据
//两次生成十万个不重复数据,即生成了20万个重复数据。去重以后应该还是十万。
long size = redisTemplate.opsForHyperLogLog().size(redisKey);
System.out.println(size);
}
最终结果:99553,精确值是十万,误差还算小
// 将3组数据合并, 再统计合并后的重复数据的独立总数.
@Test
public void testHyperLogLogUnion() {
String redisKey2 = "test:hll:02";
for (int i = 1; i <= 10000; i++) {
redisTemplate.opsForHyperLogLog().add(redisKey2, i);
}
String redisKey3 = "test:hll:03";
for (int i = 5001; i <= 15000; i++) {//和redisKey2中的数据有一定交叉
redisTemplate.opsForHyperLogLog().add(redisKey3, i);
}
String redisKey4 = "test:hll:04";
for (int i = 10001; i <= 20000; i++) {//和redisKey3 中的数据有一定交叉
redisTemplate.opsForHyperLogLog().add(redisKey4, i);
}
//总共三万条,去重以后只有两万条
String unionKey = "test:hll:union";
redisTemplate.opsForHyperLogLog().union(unionKey, redisKey2, redisKey3, redisKey4);
long size = redisTemplate.opsForHyperLogLog().size(unionKey);
System.out.println(size);
}
结果:19833,准确值是2w
演示BitMap
// 统计一组数据的布尔值
@Test
public void testBitMap() {
String redisKey = "test:bm:01";
// 记录
redisTemplate.opsForValue().setBit(redisKey, 1, true);//setBit表示按位存数据的方法1第一位为true
redisTemplate.opsForValue().setBit(redisKey, 4, true);//第4位为true
redisTemplate.opsForValue().setBit(redisKey, 7, true);//其余位置默认为0
// 查询
System.out.println(redisTemplate.opsForValue().getBit(redisKey, 0));//false
System.out.println(redisTemplate.opsForValue().getBit(redisKey, 1));//true
System.out.println(redisTemplate.opsForValue().getBit(redisKey, 2));//false
// 统计true的个数
Object obj = redisTemplate.execute(new RedisCallback() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
return connection.bitCount(redisKey.getBytes());
}
});
System.out.println(obj);
}
最终结果:
测试2
// 统计3组数据的布尔值, 并对这3组数据做OR运算.
@Test
public void testBitMapOperation() {
String redisKey2 = "test:bm:02";
redisTemplate.opsForValue().setBit(redisKey2, 0, true);
redisTemplate.opsForValue().setBit(redisKey2, 1, true);
redisTemplate.opsForValue().setBit(redisKey2, 2, true);
String redisKey3 = "test:bm:03";
redisTemplate.opsForValue().setBit(redisKey3, 2, true);
redisTemplate.opsForValue().setBit(redisKey3, 3, true);
redisTemplate.opsForValue().setBit(redisKey3, 4, true);
String redisKey4 = "test:bm:04";
redisTemplate.opsForValue().setBit(redisKey4, 4, true);
redisTemplate.opsForValue().setBit(redisKey4, 5, true);
redisTemplate.opsForValue().setBit(redisKey4, 6, true);
String redisKey = "test:bm:or";
Object obj = redisTemplate.execute(new RedisCallback() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
connection.bitOp(RedisStringCommands.BitOperation.OR,
redisKey.getBytes(), redisKey2.getBytes(), redisKey3.getBytes(), redisKey4.getBytes());//redisKey.getBytes()表示运算结果。redisKey2.getBytes(), redisKey3.getBytes(), redisKey4.getBytes()是研做运算的数据
return connection.bitCount(redisKey.getBytes());
}
});
System.out.println(obj);
//打印redisKey中的每一个值
System.out.println(redisTemplate.opsForValue().getBit(redisKey, 0));
System.out.println(redisTemplate.opsForValue().getBit(redisKey, 1));
System.out.println(redisTemplate.opsForValue().getBit(redisKey, 2));
System.out.println(redisTemplate.opsForValue().getBit(redisKey, 3));
System.out.println(redisTemplate.opsForValue().getBit(redisKey, 4));
System.out.println(redisTemplate.opsForValue().getBit(redisKey, 5));
System.out.println(redisTemplate.opsForValue().getBit(redisKey, 6));
}