redis实现博客排行榜功能

redis介绍

redis是一种高效存取的key-value存取系统, 实现了丰富的数据类型用于不同的应用场景并且支持高效的读取操作.

数据结构

String类型: 信息缓存、计数器、分布式锁

list类型: 消息队列 朋友圈的点赞列表、评论列表、排行榜

hash: 购物车 存储对象

set: 收藏夹

zset: 实时排行榜

zset的实现

zset 在内容数量大于64的时候使用了hash和skiplist两种数据结构来存储, 实现了O(log(n))的增删, O(1)的查找

跳表是一种利用空间换时间的数据结构, 通过建立多级索引加速查找;

关于增删的索引重建 使用了随机晋升的思想–randomLevel() 方法,该方法会随机生成 1~MAX_LEVEL 之间的数, 通过概率算法告诉我们这个元素需要插入到几级索引中.

(https://www.jianshu.com/p/9d8296562806, https://redisbook.readthedocs.io/en/latest/internal-datastruct/skiplist.html)
(一些面试题 https://www.cnblogs.com/shoshana-kong/p/14832434.html )

spring项目中集成redis

redis常用的客户端: Jedis Lettuce(基于Netty 线程安全的)

  1. 项目加入依赖

<dependency>

    <groupid>org.springframework.boot</groupid>

    <artifactid>spring-boot-starter-data-redis</artifactid>

</dependency>

<dependency>

    <groupid>commons-collections</groupid>

    <artifactid>commons-collections</artifactid>

    <version>2.0</version>

</dependency>

  1. 配置redis
##redis&#x914D;&#x7F6E;  Lettuce &#x548C; Jedis &#x7684;&#x90FD;&#x662F;&#x8FDE;&#x63A5; Redis Server&#x7684;&#x5BA2;&#x6237;&#x7AEF;&#x3002;
spring.redis.database=0
Redis&#x670D;&#x52A1;&#x5668;&#x5730;&#x5740;
spring.redis.host=127.0.0.1
Redis&#x670D;&#x52A1;&#x5668;&#x8FDE;&#x63A5;&#x7AEF;&#x53E3;
spring.redis.port=6379
Redis&#x670D;&#x52A1;&#x5668;&#x8FDE;&#x63A5;&#x5BC6;&#x7801;&#xFF08;&#x9ED8;&#x8BA4;&#x4E3A;&#x7A7A;&#xFF09;
spring.redis.password=
&#x8FDE;&#x63A5;&#x6C60;&#x6700;&#x5927;&#x8FDE;&#x63A5;&#x6570;&#xFF08;&#x4F7F;&#x7528;&#x8D1F;&#x503C;&#x8868;&#x793A;&#x6CA1;&#x6709;&#x9650;&#x5236;&#xFF09;
spring.redis.lettuce.pool.max-active=200
&#x8FDE;&#x63A5;&#x6C60;&#x6700;&#x5927;&#x963B;&#x585E;&#x7B49;&#x5F85;&#x65F6;&#x95F4;&#xFF08;&#x4F7F;&#x7528;&#x8D1F;&#x503C;&#x8868;&#x793A;&#x6CA1;&#x6709;&#x9650;&#x5236;&#xFF09;
spring.redis.lettuce.pool.max-wait=-1
&#x8FDE;&#x63A5;&#x6C60;&#x4E2D;&#x7684;&#x6700;&#x5927;&#x7A7A;&#x95F2;&#x8FDE;&#x63A5;
spring.redis.lettuce.pool.max-idle=10
&#x8FDE;&#x63A5;&#x6C60;&#x4E2D;&#x7684;&#x6700;&#x5C0F;&#x7A7A;&#x95F2;&#x8FDE;&#x63A5;
spring.redis.lettuce.pool.min-idle=0
&#x8FDE;&#x63A5;&#x8D85;&#x65F6;&#x65F6;&#x95F4;&#xFF08;&#x6BEB;&#x79D2;&#xFF09;
spring.redis.timeout= 1000ms
  1. 自定义redis template
package com.william.blog.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
    @Bean
    RedisTemplate<string, object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<string, object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
</string,></string,>
  1. 创建redis template操作类
package com.william.blog.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import reactor.util.annotation.Nullable;

import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
public final class RedisUtil {
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 指定缓存失效时间
     * @param key 键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time, TimeUnit t) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, t);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete((Collection) CollectionUtils.arrayToList(key));
            }
        }
    }

    /**
     * 有序集合添加之前没有的元素
     */
    public boolean zAdd(String key,Object value,double score) {
        return redisTemplate.opsForZSet().add(key, value,score);
    }

    /**
     * 获取集合中元素的排名(从大到小排序)
     * @param key
     * @param value
     * @return
     */
    public long zGetRank(String key,Object value) {
        return redisTemplate.opsForZSet().reverseRank(key, value);
    }

    /**
     * 若集合中已有此元素,则此元素score+传入参数
     * 若没有此元素,则创建元素。
     * @param key
     * @param value
     * @param score
     */
    public void zIncreamentScore(String key,Object value,double score) {
        redisTemplate.opsForZSet().incrementScore(key, value, score);
    }

    /**
     * 对集合按照分数从小到大排序(默认)
     * 指定位置区间0,-1指排序所有元素
     * 得到的值带有score
     * @param key
     * @return
     */
    public Set> zRangeWithScore(String key) {
        return redisTemplate.opsForZSet().rangeWithScores(key, 0, -1);
    }

    /**
     * 对集合按照分数从大到小排序
     * @param key
     * @return
     */
    public Set> zReverseRangeWithScore(String key){
        return redisTemplate.opsForZSet().reverseRangeWithScores(key, 0, -1);
    }

    /**
     * 获取有序集合的大小
     * @param key
     * @return
     */
    public Long zGetSize(String key) {
        return redisTemplate.opsForZSet().size(key);
    }

    /**
     * 获取key集合里面,value值的分数
     * @param key
     * @param value
     * @return
     */
    public double zGetScoreByValue(String key,Object value) {
        return redisTemplate.opsForZSet().score(key, value);
    }

    /**
     * 指定分数区间,从大到小排序
     * @param key
     * @param start
     * @param end
     * @return
     */
    public Set> zReverseRangeByScoreWithScores(String key, double start, double end){
        return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, start, end);
    }

}

实现周排行榜功能(博客)

使用的排行榜一天刷新一次, 并且每周都会清零, 同时每次都会提供当周点击量前6的文章

每次获取系统的天数作为redis的key值 从而实现一周一刷.

  1. 用户点击 增加访问量 同时设置key的ttl
long hour=System.currentTimeMillis()/(1000*60*60*24);
redisUtil.zIncreamentScore(String.valueOf(hour), articleInfo.getId(),1);
redisUtil.expire(String.valueOf(hour), 40, TimeUnit.DAYS);
  1. 查询热点文章
long hour=System.currentTimeMillis()/(1000*60*60*24);
Set> res= redisUtil.zReverseRangeWithScore(String.valueOf(hour));

前端展示:

前端使用了layui的timeline组件

redis实现博客排行榜功能

Original: https://www.cnblogs.com/wjwilliam/p/15885065.html
Author: wwilliam
Title: redis实现博客排行榜功能

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/579914/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球