redis实现热搜排行榜及历史搜索记录

2021-12-25  本文已影响0人  任未然

一. 前言

热搜排行榜实现要点: 性能/简单/时效 .
redis性能高是公认的, redis的数据结构zset有个score,可以实现排序,redis可以给key设定时效
历史搜索的实现也差不多,可以用redis的数据结构list(列表)实现,每次在头部插入数据,然后控制列表的长度就行

二. 示例

2.1 热搜排行榜-工具类

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import java.io.Serializable;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 排行榜工具
 *
 * @author 任未然
 * @date 2021/12/25
 */
public class LeaderboardUtil implements Serializable {

    /**
     * redis
     */
    private static StringRedisTemplate redisTemplate;

    public static StringRedisTemplate getRedisTemplate(){
        if(null == redisTemplate){
            synchronized (LeaderboardUtil.class){
                redisTemplate = SpringContextUtil.getBean(StringRedisTemplate.class);
                return redisTemplate;
            }
        }
        return redisTemplate;
    }

    /**
     * 排行榜添加或更新数据score
     * 排行版每天凌晨刷新一遍
     * @param key
     * @param member
     */
    public static void leaderboardAdd(String key, String member){
        // 添加或更新数据
        getRedisTemplate().opsForZSet().incrementScore(key, member, 1);
        // 设置有效期
        LocalDateTime localDateTime = LocalDateTime.of(LocalDate.now(), LocalTime.of(23, 59, 59));
        LocalDateTime now = LocalDateTime.now();
        // 时间差
        Duration between = Duration.between(now, localDateTime);
        getRedisTemplate().expire(key,between);
    }

    /**
     * 通过索引区间返回有序集合成指定区间内的成员 分数从高到低
     *
     * @param key   键
     * @param size  获取个数
     * @return 成员集合
     */
    public static List<LeaderboardDto> leaderboardGet(String key, int size) {
        List<LeaderboardDto> leaderboardDtos = null;
        try {
            Set<ZSetOperations.TypedTuple<String>> typedTuples = getRedisTemplate().opsForZSet().reverseRangeWithScores(key, 0, -1);
            if(CollectionUtils.isNotEmpty(typedTuples)){
                leaderboardDtos = typedTuples.stream().limit(size).map(stringTypedTuple -> {
                    return LeaderboardDto.builder()
                            .value(stringTypedTuple.getValue())
                            .score(stringTypedTuple.getScore())
                            .build();
                }).collect(Collectors.toList());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return leaderboardDtos;
    }
}

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
class LeaderboardDto implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty("值")
    private String value;

    @ApiModelProperty("分数")
    private Double score;
}

2.2 历史搜索-工具类

import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.io.Serializable;
import java.util.List;

/**
 * 历史搜索工具类
 *
 * @author 任未然
 * @date 2021/12/25
 */
public class HistoricalSearchUtil implements Serializable {

    /**
     * 列表最大长度
     */
    public static final int max_size = 10;

    /**
     * redis
     */
    private static ListOperations<String,String> redisTemplate;

    public static ListOperations<String,String> getRedisTemplate(){
        if(null == redisTemplate){
            synchronized (LeaderboardUtil.class){
                redisTemplate = SpringContextUtil.getBean(StringRedisTemplate.class).opsForList();
                return redisTemplate;
            }
        }
        return redisTemplate;
    }

    /**
     * 添加记录
     *
     * @param key   键
     * @param value 值
     * @return boolean
     */
    public static void lpush(String key, String value) {
        try {
            ListOperations<String, String> redisTemplate = getRedisTemplate();
            redisTemplate.leftPush(key, value);
            // 截取列表长度
            redisTemplate.trim(key,0,max_size-1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取列表数据
     *
     * @param key   键
     * @return 元素列表
     */
    public static List<String> lrange(String key) {
        try {
            ListOperations<String, String> redisTemplate = getRedisTemplate();
            return redisTemplate.range(key, 0, -1);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读