7.7 热帖排行

  • 在点赞,评论,收藏,加精等地方都要重新计算帖子分数。
  • 使用redis中的set集合数据结构,在以上操作处理中, 往set集合中存入帖子id
  • 设置一个定时任务,每隔半小时去重新计算帖子的分数
    • 具体为: 根据set中的id从数据库中查询出DiscussPost, 利用commentCount, likeCount等字段计算score,
    • 配置JobDetail和Trigger
  • 计算完了以后需要将帖子同步到数据库和ElasticSerach服务器中去
  • 再提供一个根据热度排行的服务处理方法

规划key

    private static final String PREFIX_POST = "post";    
//帖子分数
    public static  String getPostScoreKey(){
        return PREFIX_POST + SPLIT + "score";
    }

再评论,点赞,加精等地方, 存入discusspostId至Redis的set集合中

 

    //加精
    @RequestMapping(path = "/wonderful", method = RequestMethod.POST)
    @ResponseBody
    public String setWonderful(int id){
        discussPostService.updateStatus(id, 1);

        //触发发帖事件,把数据重新同步到es服务器中去
        Event event = new Event()
                .setTopic(TOPIC_PUBLISH)
                .setUserId(hostHolder.getUser().getId())
                .setEntityType(ENTITY_TYPE_POST)
                .setEntityId(id);
        eventProducer.fireEvent(event);

        //计算帖子分数
        String redisKey = RedisKeyUtil.getPostScoreKey();
        redisTemplate.opsForSet().add(redisKey, id);
        return CommunityUtil.getJSONString(0);
    }

设置定时任务

package com.newcoder.community.quartz;

import com.newcoder.community.entity.DiscussPost;
import com.newcoder.community.service.DiscussPostService;
import com.newcoder.community.service.ElasticsearchService;
import com.newcoder.community.service.LikeService;
import com.newcoder.community.util.CommunityConstant;
import com.newcoder.community.util.RedisKeyUtil;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.RedisTemplate;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class PostScoreRefreshJob implements Job, CommunityConstant {
    private static final Logger logger = LoggerFactory.getLogger(PostScoreRefreshJob.class);

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private DiscussPostService discussPostService;

    @Autowired
    private LikeService likeService;

    @Autowired
    private ElasticsearchService elasticsearchService;

    //牛客记元
    private static final Date epoch;
    static {
        try {
            epoch = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-08-01 00:00:00");
        } catch (ParseException e) {
            throw  new RuntimeException("初始化牛客纪元失败", e);
        }
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("execute.......");
        String redisKey = RedisKeyUtil.getPostScoreKey();
        BoundSetOperations operations = redisTemplate.boundSetOps(redisKey);

        if(operations.size() == 0){
            logger.info("[任务取消] 没有需要刷新的帖子!");
            return;
        }

        logger.info("[任务开始] 正在刷新的帖子分数: " + operations.size());
        //每次刷新一个帖子的分数即可
        while(operations.size() > 0){
            this.refresh((Integer) operations.pop());
        }

        logger.info("[任务开始] 帖子分数刷新完毕");
    }

    private void refresh(int postId){
        DiscussPost post = discussPostService.findDiscussPostById(postId);

        if(post == null){
            logger.error("该帖子不存在: id =" + post.getId());
            return;
        }

        //是否加精
        boolean wonderful = post.getStatus() == 1;
        //评论数量
        int commentCount = post.getCommentCount();
        //点赞数量
        long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, postId);

        //计算权重
        double w = (wonderful ? 75 : 0) + commentCount * 10 + likeCount * 2;
        //分数 = 帖子权重 + 距离天数
        double score = Math.log10(Math.max(w, 1))
                + (post.getCreateTime().getTime() - epoch.getTime()) / (1000 * 3600 * 24);

        //更新帖子的分数
        discussPostService.updateScore(postId,score);
        post.setScore(score);
        //同步搜索数据
        elasticsearchService.saveDiscussPost(post);
    }
}

配置定时任务

    // 配置JobDetail 刷新帖子分数任务
    @Bean
    public JobDetailFactoryBean postScoreRefreshJobDetail(){
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(PostScoreRefreshJob.class);
        factoryBean.setName("postScoreRefreshJob");//任务的名字
        factoryBean.setGroup("communityJobGroup");//任务的所属组
        factoryBean.setDurability(true);//是不是长久保存,哪怕以后任务的触发器都没了,是不是还会一直保存
        factoryBean.setRequestsRecovery(true);//任务是不是可恢复的
        return factoryBean;
    }
    //配置Trigger(SimpleTriggerFactoryBean, CronTriggerFactoryBean)
    @Bean
    public SimpleTriggerFactoryBean postScoreRefreshTrigger(JobDetail postScoreRefreshJobDetail){
        SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
        factoryBean.setJobDetail(postScoreRefreshJobDetail);//对哪个job生效
        factoryBean.setName("postScoreRefreshTrigger");//给trigger取个名字
        factoryBean.setGroup("communityTriggerGroup");//给trigger取一个组名
        factoryBean.setRepeatInterval(1000 * 60 * 2);//2分钟刷新一次
        factoryBean.setJobDataMap(new JobDataMap());//需要存储job的一些状态
        return factoryBean;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值