如何用Redis zset做一个商品排行榜

想做一个根据用户对商品的点赞数的排行榜,考虑到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);
}

 

 

你可能感兴趣的:(springboot,Java,redis,java)