最热门排行
考虑redis的zset结构,创建一个top的 key, 子key为热点,score 为关注度。每次关注数增加时调用zincrby,增加score。需要获取时,调用zrevrange 获取top10的结果即可。如果觉得保存热点作为key代价高,就可以结合mysql,做一个索引映射吧。redis 保存归一化的值。mysql保存真实数据,需要获取的时候再去mysql检索就好。
1、实现接口
package com.strap.mydemo.redis;
import java.util.List;
/**
* <p>热点排行版</p>
*
* @author strap
*/
public interface HotRanking {
/**
* 当前排行榜的唯一key
*/
String getRankingNameKey();
/**
* 往排行榜添加记录,如果记录存在,就增加其分数,如果不存在则创建并使用score作为基础份,最后返回当前排行版内其分数值,
*/
Double addTarget(String key, double score);
/**
* 按正序(倒序)获取排行版中的ID列表
*/
List<String> getRankList(Integer pageSize, boolean desc);
/**
* 按正序(倒序)获取排行版中的某个ID的排位
*/
Long getRank(String key, boolean desc);
/**
* 清空排行版
*/
Boolean deleteRanking();
}
2、实现抽象类
package com.strap.mydemo.redis;
import cn.hutool.core.collection.CollectionUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* <p></p>
*
* @author strap
*/
public abstract class HotRankingAbstract implements HotRanking{
@Resource
protected RedisTemplate<String, Object> redisTemplate;
public HotRankingAbstract() {
}
@Override
public Double addTarget(String key, double score) {
return redisTemplate.opsForZSet().incrementScore(getRankingNameKey(), key, score);
}
@Override
public Boolean deleteRanking() {
return redisTemplate.delete(getRankingNameKey());
}
/**
* 倒序获取对应key排名
*/
public Long getRank(String key) {
return getRank(key, true);
}
/**
* 按分数倒序获取值
*/
public List<String> getRankList(Integer pageSize) {
return getRankList(pageSize, true);
}
@Override
public List<String> getRankList(Integer pageSize, boolean desc) {
Set<ZSetOperations.TypedTuple<Object>> typedTuples = desc ?
redisTemplate.opsForZSet().reverseRangeWithScores(getRankingNameKey(), 0, pageSize - 1)
: redisTemplate.opsForZSet().rangeWithScores(getRankingNameKey(), 0, pageSize - 1);
return CollectionUtil.isEmpty(typedTuples) ? Collections.emptyList() : typedTuples.stream().map(i -> String.valueOf(i.getValue())).collect(Collectors.toList());
}
@Override
public Long getRank(String key, boolean desc) {
Long rank = desc ? redisTemplate.opsForZSet().reverseRank(getRankingNameKey(), key)
: redisTemplate.opsForZSet().rank(getRankingNameKey(), key);
return rank == null ? -1L : rank + 1;
}
}
3、实现子类
package com.strap.mydemo.redis;
import org.springframework.stereotype.Component;
/**
* <p></p>
*
* @author strap
*/
@Component
public class BookHotRanking extends HotRankingAbstract{
public BookHotRanking() {
}
@Override
public String getRankingNameKey() {
return "hot:ranking:book";
}
}
4、测试
for (int i = 0; i < 20; i++) {
bookHotRanking.addTarget(RandomUtil.randomInt(5) + "", 1);
}
log.info(bookHotRanking.getRankList(5));
log.info(bookHotRanking.getRankList(3, false));
log.info(bookHotRanking.getRank("1", false));
log.info(bookHotRanking.getRank("7"));
bookHotRanking.deleteRanking();