想做一个根据用户对商品的点赞数的排行榜,考虑到Redis 的zset 的可以根据分数排序,今天就来玩一下。文中使用springboot 的redisTemplate 操作redis,可以参考之前写的一篇操作redis 各种数据结构的文章:redisTemplate分别存取redis的string/list/set/zset/hash等数据类型 这里会用到里面介绍的redisTemplate.
首先建立一个实体类,用于测试,商品数据统一使用springboot jpa 进行操作:
/**
* @author chenxiangweifeng
* 商品实体类
*/
@Data
@Entity
@Table(name = "tb_product")
public class Product {
@Id
@Column(name = "id")
private String id;
@Column(name = "name")
private String name;
@Column(name = "price")
private Double price;
}
数据结构的设计:在redis 中建立一个zset 类型的key,其中的每个member 用商品的ID充当,分数使用用户对该商品的点赞数量表示,这样Redis就可以根据点赞数对库中的商品进行排序,从而我们可以顺利获取商品的点赞排行榜 。
用户每一次对商品点赞,我们就可以根据该商品的ID,增加zset中的该member的score,如果该member不存在就新增,如果存在直接增加其分数:
@Service
public class RedisRankService {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private ProductRepository productRepository;
// 商品点赞的redis key
private String key = "product:praise";
/**
* @param id 商品的ID
*/
public void GiveAPraise(String id){
// 每次点赞分数每次增加1,如果Redis中有这个key就把分数+1,如果没有就会新增该值
redisTemplate.opsForZSet().incrementScore(key,id,1);
}
}
利用zset 根据分数排序的特性,倒序取出(按照分数从大到小)就可以取出点赞数排行前10的商品ID,再根据商品ID到Redis中取出对应的点赞数,以及借助jpa从数据库中根据商品ID取出这些商品的全部信息就非常easy了。
/**
* @return 取出点赞数排名前10的商品
*/
public List queryTop10Product(){
List vos = new ArrayList<>();
// 按照分数从高到低进行排序,并取出对应的点赞数量
Set idSets = redisTemplate.opsForZSet().reverseRange(key, 0, 9);
List products = productRepository.queryByIdIn(idSets);
Map idProductMap = CollectionUtils.isEmpty(products)? Maps.newHashMap() :
products.stream().collect(Collectors.toMap(Product::getId, Function.identity(),(e1,e2)->e2));
for (String id : idSets){
Double score = redisTemplate.opsForZSet().score(key, id);
ProductVo vo = new ProductVo();
Product p = idProductMap.getOrDefault(id,new Product());
vo.setId(id);
vo.setName(p.getName());
vo.setPrice(p.getPrice());
vo.setScore(score.intValue());
vos.add(vo);
}
return vos;
}
操作数据我们使用spingboot jpa, 对于一些简单的查询方法可以不用写SQL,直接使用jpa规定的关键词构造查询方法即可,比如这里根据批量的商品ID查询所有商品详情:
/**
* @author chenxiangweifeng
* @date 2021-02-02
* jpa操作商品实体类的repository
*/
@Repository
public interface ProductRepository extends JpaRepository, JpaSpecificationExecutor {
/**
* @param ids 产品id list
* @return 根据ids 批量查询产品详情
*/
List queryByIdIn(Set ids);
}