资料来源 极客时间 Redis 亚风 原文视频:https://u.geekbang.org/lesson/535?article=681063
同⼀个⽤户只能点赞⼀次,再次点击则取消点赞
如果当前⽤户已经点赞,则点赞按钮⾼亮实现
展示点赞数量并展示点赞top3(时间)的⽤户信息
@RestController
public class BlogController {
@Autowired
StringRedisTemplate stringRedisTemplate;
/**
* 博客点赞功能,不需要排行榜
* @param userID
* @param blogID
* @return
*/
@GetMapping("/likeBlog")
public String likeBlog(String userID, String blogID) {
String key = "blog" + ":" + blogID;
Boolean member = stringRedisTemplate.opsForSet().isMember(key, userID);
if (Boolean.TRUE.equals(member)) {
System.out.println("已点赞,取消点赞");
stringRedisTemplate.opsForSet().remove(key, userID);
} else {
System.out.println("没有点赞,进行点赞");
stringRedisTemplate.opsForSet().add(key, userID);
}
return "OK";
}
/**
* 博客点赞功能,需要排行榜
* @param userID
* @param blogID
* @return
*/
@GetMapping("/likeBlogTop")
public String likeBlogTop(String userID, String blogID) {
String key = "blog" + ":" + blogID;
Double score = stringRedisTemplate.opsForZSet().score(key, userID);
if (Objects.nonNull(score)) {
System.out.println("已点赞,取消点赞");
stringRedisTemplate.opsForZSet().remove(key, userID);
} else {
System.out.println("没有点赞,进行点赞");
// 时间 越靠前 得分越多
stringRedisTemplate.opsForZSet().add(key, userID, System.currentTimeMillis());
}
return "OK";
}
/**
* 博客点赞功能,返回top3
* @param userID
* @param blogID
* @return
*/
@GetMapping("/getBlog")
public Blog getBlog(String blogID, String userID) {
String key = "blog" + ":" + blogID;
Long count = stringRedisTemplate.opsForZSet().size(key);
Blog blog = new Blog();
blog.setBlogID(blogID);
blog.setLikeCount(count);
blog.setIsLike(Objects.nonNull(stringRedisTemplate.opsForZSet().score(key, userID)) );
Set<String> likeUsers = stringRedisTemplate.opsForZSet().range(key, 0, 2);
blog.setLikeUsers(likeUsers);
return blog;
}
}
GEO就是Geolocation的简写形式,代表地理坐标。Redis在3.2版本中加⼊了对GEO的⽀持,允许存储地理坐标信息,帮助我们根据经纬度来检索数据。 其原理是geohash
GEOADD:添加⼀个地理空间信息,包含:经纬度、值
GEODIST:计算指定的两个点之间的距离并返回
GEOHASH:将指定member的坐标转为hash字符串形式并返回
GEOPOS:返回指定member的坐标
GEORADIUS:指定圆⼼、半径,找到该圆内包含的所有member,并按照与圆⼼之间的距离排序后返回。6.2以后已废弃。
GEOSEARCH:在指定范围内搜索member,并按照与指定点之间的距离排序后返回。范围可以是圆形或矩形。6.2新功能。
geohash 相关知识
@RestController
public class GeoController {
@Autowired
StringRedisTemplate stringRedisTemplate;
/**
* 就算距离
* @param x
* @param y
* @return
*/
@RequestMapping("radius")
@ResponseBody
public List<GeoResult<RedisGeoCommands.GeoLocation<String>>> radius(double x, double y){
RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
.limit(5)
//包含成员距离中心点的距离
.includeDistance();
GeoResults<RedisGeoCommands.GeoLocation<String>> result = stringRedisTemplate.opsForGeo().radius("near",
new Circle(new Point(x,y),new Distance(10000, Metrics.KILOMETERS)),args);
return result.getContent();
}
/**
* 添加地理坐标系
* @return
*/
@RequestMapping("putLongLat")
public String putLongLat() {
double x = 130.5423;
double y = 30.54235;
String key = "near";
String member;
for (int i = 0; i < 5; i ++) {
x += i * 0.01;
y += i * 0.01;
member = "po" + i;
stringRedisTemplate.opsForGeo().add(key, new Point(x, y), member);
}
return "OK";
}
}
把每⼀个bit位对应当⽉的每⼀天,形成了映射关系。⽤0和1标示业务状态,这种思路就称为位图(BitMap),Redis中是利⽤string类型数据结构实现BitMap,因此最⼤上限是512M,转换为bit则是 2^32 个bit位。
BitMap的操作命令有:
SETBIT:向指定位置 (offset)存⼊⼀个0或1
GETBIT:获取指定位置 (offset)的bit值
BITCOUNT:统计 BitMap中值为1的bit位的数量
BITFIELD:操作(查询、修改、⾃增) BitMap中bit数组中的指定位置
(offset)的值
BITFIELD_RO:获取BitMap中bit数组,并以⼗进制形式返回
BITOP:将多个BitMap的结果做位运算(与、或、异或)
BITPOS:查找bit数组中指定范围内第⼀个0或1出现的位置
@RestController
public class SignController {
@Autowired
StringRedisTemplate stringRedisTemplate;
@RequestMapping("sign")
@ResponseBody
public String sign(String userId) {
LocalDateTime now = LocalDateTime.now();
String key= "sign:"+userId+ ":"+now.format(DateTimeFormatter.ofPattern("yyyyMM"));
// 将当天的位变为 1
stringRedisTemplate.opsForValue().setBit(key,now.getDayOfMonth()-1,true);
return "SUCCESS";
}
@RequestMapping("signCount")
@ResponseBody
public Long signCount(String userId) {
LocalDateTime now = LocalDateTime.now();
String key= "sign:"+userId+ ":"+now.format(DateTimeFormatter.ofPattern("yyyyMM"));
List<Long> result = stringRedisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.
unsigned(now.getDayOfMonth())).valueAt(0));
if(CollectionUtils.isEmpty(result)){
return 0L;
}
Long num = result.get(0);
// 统计连续签到数量
Long count = 0L;
while(true){
if((num&1)==0){
break;
}else{
count++;
}
num >>>=1;
}
return count;
}
}
UV:全称Unique Visitor,也叫独⽴访客量,是指通过互联⽹访问、浏览这个⽹⻚的⾃然⼈。1天内同⼀个⽤户多次访问该⽹站,只记录1次。
PV:全称Page View,也叫⻚⾯访问量或点击量,⽤户每访问⽹站的⼀个⻚⾯,记录1次PV,⽤户多次打开⻚⾯,则记录多次PV。往往⽤来衡量⽹站的流量。
Hyperloglog(HLL)是从Loglog算法派⽣的概率算法,⽤于确定⾮常⼤的集合的基数,⽽不需要存储其所有值。
Redis中的HLL是基于string结构实现的(不允许出现相同元素),单个HLL的内存永远⼩于16kb,作为代价,其测量结果是概率性的,有⼩于0.81%的误差。不过对于UV统计来说,这完全可以忽略。
PFADD key element | [elements] #也就是支持数组 #命令用于将一个或多个元素添加到 HyperLogLog 中。如果 HyperLogLog 不存在,该命令将创建一个新的 HyperLogLog。如果 HyperLogLog已经存在,它将更新估计的基数。
PFCOUNT key | [keys] #也支持数组 #PFCOUNT 是 Redis 中用于获取 HyperLogLog(基数估计算法)数据结构的估计基数(不同元素的数量)的命令。该命令用于返回给定 HyperLogLog 的近似基数,即集合中的不同元素数量的估计值。
PFMERGE destkey sourcekey [sourcekey...] #合并key