当前位置:网站首页>Number 16, top posts
Number 16, top posts
2022-07-31 02:40:00 【A snicker】
1、Post scores are time-dependent,而且点赞,Collections and other operations are very high frequency,Generally, post scores are calculated through timed tasks(分布式定时任务 Spring Quartz)
2、Put posts with changed scores in the cache,Time to time to calculate the posts in the cache(Redis)
1、Put the post that needs to calculate the scoreRedis中
1、生成RedisKey
2、When an action that affects the post score occurs,Put the post inRedis
RedisKeyUtil.java
// 帖子分数
public static String getPostScoreKey() {
return PREFIX_POST + SPLIT + "score";
}
DiscussPostController.java
A)When posting a new post,将帖子id放入Redis(Give the post an initial score):RedisKey:postId 存放在Set里.
@PostMapping("/add")
@ResponseBody
public String addDiscussPost(String title, String content) {
...
// 计算帖子分数
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, post.getId());
}
B)加精、评论、When liking the action,Also put the post inRedis
// 加精 HomeController.java
@PostMapping("/wonderful")
@ResponseBody
public String setWonderful(int id) {
discussPostService.updateStatus(id, 1);
...
// 计算帖子分数
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, id);
}
// 评论 CommentController.java
@PostMapping("/add/{discussPostId}")
public String addComment(@PathVariable("discussPostId") int discussPostId, Comment comment) {
if (comment.getEntityType() == ENTITY_TYPE_POST) {
...
// 计算帖子分数
String redisKey = RedisKeyUtil.getPostScoreKey();
redisTemplate.opsForSet().add(redisKey, discussPostId);
}
2、使用Quartz实现定时任务
1、Job接口实现
quartz包下 PostScoreRefreshJob 类
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 context) throws JobExecutionException {
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 = " + postId);
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);
}
}
- Niu Ke era domain:private static final Date epoch,由于epoch只需要初始化一次,Initialize in a static code block
- 使用BoundSetOperations 绑定 Key,BoundSetOperationsis a bindingkey的对象,We can use this object to ANDkey相关的操作.
- 从Redis里取数据,若没有数据,Return directly after logging.若Set为空,对每个postId执行 refresh 方法.
refreshA method to refresh a post:
1、根据帖子id查找post实体
2、Determine whether to add refined、评论数量、点赞数量,计算分数(getTime() Get the millisecond value)
3、更新帖子分数
4、同步搜索数据
5、对Quartz进行配置:Time interval in milliseconds
对Quartz进行配置
// 配置 -> 数据库 -> 调用
@Configuration
public class QuartzConfig {
// 刷新帖子分数任务
@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);
factoryBean.setName("postScoreRefreshTrigger");
factoryBean.setGroup("communityTriggerGroup");
factoryBean.setRepeatInterval(1000 * 60 * 5);
factoryBean.setJobDataMap(new JobDataMap());
return factoryBean;
}
}
3、Home page interface processing
1、Sort posts by hottest
对 selectDiscussPostsThe method can be refactored
@Mapper
public interface DiscussPostMapper {
List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit, int orderMode);
// 增加了一个orderMode参数: orderMode=0 时按照“最新” 排序,orderMode=1 时按照“最热” 排序
}
discusspost-mapper.xml
<select id="selectDiscussPosts" resultType="DiscussPost">
select <include refid="selectFields"></include>
from discuss_post
where status != 2
<if test="userId!=0">
and user_id = #{
userId}
</if>
<if test="orderMode==0">
order by type desc, create_time desc
</if>
<if test="orderMode==1">
order by type desc, score desc, create_time desc
</if>
limit #{
offset}, #{
limit}
</select>
2、所有调用 selectDiscussPosts 的地方进行修改
3、HomeController:
从前端获取ordermode参数,and spell in path returned to the template
@RequestMapping(path = "/index", method = RequestMethod.GET)
public String getIndexPage(Model model, Page page,
@RequestParam(name = "orderMode", defaultValue = "0") int orderMode) {
// 1.默认orderMode=0,For example, when visiting the home page
// 方法调用钱,SpringMVC会自动实例化Model和Page,并将Page注入Model.
// 所以,在thymeleaf中可以直接访问Page对象中的数据.
page.setRows(discussPostService.findDiscussPostRows(0));
page.setPath("/index?orderMode=" + orderMode); // 2.修改Page的路径,加上orderMode参数
// 3.Use the refactored onediscussPostService
List<DiscussPost> list = discussPostService
.findDiscussPosts(0, page.getOffset(), page.getLimit(), orderMode);
List<Map<String, Object>> discussPosts = new ArrayList<>();
if (list != null) {
for (DiscussPost post : list) {
Map<String, Object> map = new HashMap<>();
map.put("post", post);
User user = userService.findUserById(post.getUserId());
map.put("user", user);
long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, post.getId());
map.put("likeCount", likeCount);
discussPosts.add(map);
}
}
model.addAttribute("discussPosts", discussPosts);
model.addAttribute("orderMode", orderMode);
return "/index";
}
4、index.html
1)th:href Hyperlink modification,传入orderMode 参数
2)由orderMode The parameter determines whether there is active 参数
<!-- 筛选条件 -->
<ul class="nav nav-tabs mb-3">
<li class="nav-item">
<a th:class="|nav-link ${orderMode==0?'active':''}|" th:href="@{/index(orderMode=0)}">最新</a>
</li>
<li class="nav-item">
<a th:class="|nav-link ${orderMode==1?'active':''}|" th:href="@{/index(orderMode=1)}">最热</a>
</li>
</ul>
边栏推荐
- Inter-vlan routing + static routing + NAT (PAT + static NAT) comprehensive experiment
- AI software development process in medical imaging field
- 1. Non-type template parameters 2. Specialization of templates 3. Explanation of inheritance
- 8. Unified exception handling (controller notifies @ControllerAdvice global configuration class, @ExceptionHandler handles exceptions uniformly)
- 【银行系列第一期】中国人民银行
- Modbus on AT32 MCU
- The application of AI in the whole process of medical imaging equipment
- Tower of Hanoi problem
- 19.支持向量机-优化目标和大间距直观理解
- 10、Redis实现点赞(Set)和获取总点赞数
猜你喜欢

221. Largest Square

How to do a startup CTO?

7、私信列表

Basic introduction to ShardingJDBC

19.支持向量机-优化目标和大间距直观理解

Detailed explanation of STP election (step + case)

JS 函数 this上下文 运行时点语法 圆括号 数组 IIFE 定时器 延时器 self.备份上下文 call apply

Drools Rule Properties, Advanced Syntax

19. Support Vector Machines - Intuitive Understanding of Optimization Objectives and Large Spacing

SQL注入 Less54(限制次数的SQL注入+union注入)
随机推荐
String为什么不可变?
真正的CTO,是一个懂产品的技术人
There is a problem with the multiplayer-hlap package and the solution cannot be upgraded
YOLOV5学习笔记(三)——网络模块详解
golang GUI for nuxui — HelloWorld
你们程序员为什么不靠自己的项目谋生?而必须为其他人打工?
CentOS7下mysql5.7.37的卸载【完美方案】
Software Testing Defect Reporting - Definition, Composition, Defect Lifecycle, Defect Tracking Post-Production Process, Defect Tracking Process, Purpose of Defect Tracking, Defect Management Tools
cudaMemcpy study notes
Discourse Custom Header Links
Static route analysis (the longest mask matching principle + active and standby routes)
Tower of Hanoi problem
公司官网建站笔记(六):域名进行公安备案并将备案号显示在网页底部
ShardingJDBC usage summary
局域网电脑硬件信息收集工具
How to design the changing system requirements
SQL注入 Less54(限制次数的SQL注入+union注入)
开题报告之论文框架
The comprehensive result of the case statement, do you know it?[Verilog Advanced Tutorial]
Modbus on AT32 MCU