首先呢,今天也是元旦的最后一天假期了,大家是不是在元旦的时候也给自己立了好多的目标呢,我呢,今年就立个小目标,争取,以后的每1~2周可以有时间来写一篇文章,不管好坏,希望在明年的这个时候自己的博客里面最少可以看得出来,自己今年的一些努力。
这里我就不说Redis的基本结构了,大家在平时的工作的时候都已经使用的滚瓜烂熟了,自己在平时的面试的时候想想也就能知道,我在面试过程中,这个五个基本类型都说不出来的几乎是没有的了。那么就来说说今天的主要的几个数据类型BitMap、GeoHash、HyperLogLog。
BitMap,位图,二进制里的一位一位的,这个平时的时候真的并不知道怎么使用的,使用过的地方好像就使用给用户的一个操作记录到这个里面,这个例子呢,我就不写了,如果小伙伴自己感兴趣可以去百度看看。
GeoHash,这是一个记录位置的数据结构,这里呢,我就写了两个小例子,一个是统计两个人之间的距离有多远,一个是附近的人的例子。
public static void main(String[] args) throws Exception{
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.geoadd("geomap_demo", 116.404269,39.91405, "张三");
jedis.geoadd("geomap_demo", 116.417779,39.914382, "李四");
jedis.geoadd("geomap_demo", 116.417707,39.916208, "王五");
Double dis = jedis.geodist("geomap_demo", "张三", "李四", GeoUnit.KM);
System.out.println("张三和李四的距离是:"+ dis + "KM");
List<GeoRadiusResponse> geoRadiusResponses = jedis.georadiusByMember("geomap_demo", "李四", 2, GeoUnit.KM);
geoRadiusResponses = geoRadiusResponses.stream().filter(resp -> !"李四".equals(resp.getMemberByString())).collect(Collectors.toList());
System.out.println("李四附近2KM的人有:"+ geoRadiusResponses.stream().map(GeoRadiusResponse::getMemberByString).collect(Collectors.toList()));
}
第一个是直接计算的张三和李四的距离是多少,我们直接把对应的经纬度找好了,然后复制就可以了,这个功能是不是有点像地图里面的距离某个地方多少KM的功能呢。
第二个是直接找到李四附近的人,前提是先把附近的人的坐标都输入好,然后在使用jedis.georadiusByMember,然后给号对应的值就可以了,这个功能是不是和附近人的功能很像。
HyperLogLog,这个的结构呢,是一个统计和去重使用的,但是呢,会有一定的误差,大概在1%左右的一个误差值。但是如果需要统计上百万,上千万的数据的时候,如果你要保证没有误差的话,使用Set的大小和使用HyperLogLog的大小,还是差很多很多的。第一个是可以统计网站的UV(浏览用户数),统计的时候还可以合并,还可以用作去重,这个可以用作大批量的去重。
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
List<String> list = new ArrayList<>();
for (int i = 100; i < 2000; i++){
list.add(String.valueOf(i));
}
// 给hyper_demo_1用户的数据,大概1900个左右
jedis.pfadd("hyper_demo_1", list.toArray(new String[list.size()]));
// 这里统计对应的数据个数
long count = jedis.pfcount("hyper_demo_1");
System.out.println("统计UV的个数:" + count);
// 给hyper_demo_2赋值
list = new ArrayList<>();
for (int i = 1900; i < 3000; i++){
list.add(String.valueOf(i));
}
jedis.pfadd("hyper_demo_2", list.toArray(new String[list.size()]));
// 给hyper_demo_3赋值
list = new ArrayList<>();
for (int i = 2900; i < 4000; i++){
list.add(String.valueOf(i));
}
jedis.pfadd("hyper_demo_3", list.toArray(new String[list.size()]));
// 这里"hyper_demo_1","hyper_demo_2","hyper_demo_3"合并到hyper_demo
jedis.pfmerge("hyper_demo_0", "hyper_demo_1", "hyper_demo_2", "hyper_demo_3");
// 这里看看hyper_demo最后的个数是多少
count = jedis.pfcount("hyper_demo_0");
System.out.println("统计合并后的UV的个数:" + count);
// 这个地方第一次添加张三
Long pfadd = jedis.pfadd("hyper_demo_n", "张三");
System.out.println("添加张三是否成功:" + (pfadd == 1 ? "是":"否"));
// 这个地方第二次添加张三
pfadd = jedis.pfadd("hyper_demo_n", "张三");
System.out.println("添加张三是否成功:" + (pfadd == 1 ? "是":"否"));
}
第一个是就是直接去统计网站的UV数量,这个就是直接把数据放到里面看最后的结果就好了。
第二个是把好几个HyperLogLog都合并到一个里面,这个直接也会统计出来这几个里面去重后的结构,这个应用场景就是,我们每一天的UV都会记录下来,但是这个时候老板需要我们把这一周的UV给他,这个时候使用这个合并的功能就可以了。
第三个就是一个简单的去重的功能,在平时的工作中,如果遇到那种有很大批量的数据,你不知道怎么判断下一个是不是需要去重的时候,使用这个还是一个不错的选择的。
HyperLogLog其实在很多的场景面试题的时候回用到,这个就看大家遇到的时候会不会想到,虽然自己的答案并不一定是正确的,但是尽量保证的我们在面试的时候,面对这种场景面试题的时候,我们有我们自己的解题思路,这样面试官最少会多看一眼,你的机会也可以多一些。
我记得当初在我面试的时候,面试问过我一个问题,就是如果有一个上千万的商品详情页的数据存储在Redis里面,这个时候我是怎么来统计那个商品是在Redis里面的,那个是没有在这个里面的,当然这个里面需要注意的是,如果缓存里面的数据被LRU清楚了,这个HyperLogLog是并不知道的。
注:本人并没有什么大厂经验,如果有什么写的不好或者不对的地方还请见谅。