redis高级数据类型
HyperLogLog (超级日志)
- 采用的是一种基数算法,用于完成独立总数的统计
- 占据空间小,无论统计多少数据,只存12k的内存空间
- 不准确的统计算法,标准误差在 0.81%
例子: 用于对巨量的数据进行去重复的操作
// 统计20万个重复数据的独立总数
@Test
public void testHyperLogLog(){
String redisKey = "test:hll:01";
for (int i = 1; i <= 1000; i++) {
redisTemplate.opsForHyperLogLog().add(redisKey,i);
}
for (int i = 1; i <= 1000; i++) {
int r = (int)(Math.random()*100000 + 1);
redisTemplate.opsForHyperLogLog().add(redisKey,r);
}
// 统计重复的结构
long size = redisTemplate.opsForHyperLogLog().size(redisKey);
System.out.println(size);
}
- 还可以将多组数据,进行合并以后再去重复
// 将三组数据进行合并 , 再统计他们一共的去重复后的独立总数
@Test
public void testHyperLogLogUnion(){
String redisKey2 = "test:hll:02";
for(int i=1;i<=1000;i++){
redisTemplate.opsForHyperLogLog().add(redisKey2,i);
}
String redisKey3 = "test:hll:03";
for(int i=1;i<=1500;i++){
redisTemplate.opsForHyperLogLog().add(redisKey3,i);
}
String redisKey4 = "test:hll:04";
for(int i=1000;i<=2000;i++){
redisTemplate.opsForHyperLogLog().add(redisKey4,i);
}
// 合并之后会产生一个新的key,所以我们在之前就要进行定义一个新的key
String unionKey = "test:hll:union";
redisTemplate.opsForHyperLogLog().union(unionKey,redisKey3,redisKey2,redisKey4);
long size = redisTemplate.opsForHyperLogLog().size(unionKey);
System.out.println(size);
}
Bitmap (位图)
- 不是一种独立的数据结构,说白了就是一个字符串
- 支持按位存取数据,可以将其看成是byte数组
- 适合存储大量的连续的数据的布尔值
例子: 签到记录的统计
// 统计一组数据的布尔值
@Test
public void testBitmap(){
String redisKey = "test:bm:01";
// 记录 key,第几位存值,布尔值
redisTemplate.opsForValue().setBit(redisKey,1,true);
redisTemplate.opsForValue().setBit(redisKey,4,true);
redisTemplate.opsForValue().setBit(redisKey,7,true);
// 查询
System.out.println(redisTemplate.opsForValue().getBit(redisKey,0));
System.out.println(redisTemplate.opsForValue().getBit(redisKey,1));
System.out.println(redisTemplate.opsForValue().getBit(redisKey,2));
// 统计多少个数
Object obj = redisTemplate.execute(new RedisCallback() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
return connection.bitCount(redisKey.getBytes());
}
});
System.out.println(obj);
}
- 同样的,位图也可以将多组数据进行合并运算,可以进行 与或非 的运算。
// 统计三组数据的布尔值,同时对三组数据进行做 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);
// 同理 合并后的结果需要存放在新的地方,所以我们这里建立一个新的key
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());
return connection.bitCount(redisKey.getBytes());
}
});
System.out.println(obj);
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));
}