当前位置:网站首页>Use redis' sorted set to make weekly hot Reviews
Use redis' sorted set to make weekly hot Reviews
2022-06-25 01:15:00 【Java confidant_】
Click on the official account , Practical technical articles Know in time 
General idea
Thought analysis
Do weekly hot discussion , Cache should be used to do , If you check the library directly , It puts pressure on the database . If you do it with a cache , use Redis It's more appropriate to cache .

# utilize Redsi add to Data command
# day:1 Refer to 1 When no. post:1 The first article added 10 comments .
# Back 6 post:2 refer to stay 1 The second part of No. 2 added 6 comments
zadd day:1 10 post:1 6 post:2
zadd day:2 10 post:1 6 post:2
zadd day:3 10 post:1 6 post:2
....
zadd day:8 10 post:1 6 post:2
# That's it 7 A record of days The above command can help us record 7 Number of all comments in days . But it hasn't helped us figure out who is the most commented . see Redis Of sorted set An ordered set has a command that can help us achieve this function .
This command can help us achieve union , We just have to take 7 You can find out by combining the comments of days .

# Redis command
# It means union, put this 7 Days of Put it in a new collection The new set is week:rank In this way, there will be our... In this new collection
#7 Days of records
union week:rank 7 day:1...day:8Redis Command practice to see
Local command line test

127.0.0.1:6379> ping
PONG
127.0.0.1:6379> zadd day:1 10 post:1
(integer) 1
127.0.0.1:6379> zadd day:2 10 post:1
(integer) 1
127.0.0.1:6379> zadd day:3 10 post:1
(integer) 1
127.0.0.1:6379> zadd day:1 5 post:2
(integer) 1
127.0.0.1:6379> zadd day:2 5 post:2
(integer) 1
127.0.0.1:6379> zadd day:3 5 post:2
(integer) 1
127.0.0.1:6379> keys *
1) "day:1"
2) "day:2"
3) "day:3" View the leaderboard command of the day ZRevrange
127.0.0.1:6379> zrevrange day:1 0 -1 withscores
1) "post:1"
2) "10"
3) "post:2"
4) "5"
127.0.0.1:6379>Weekly review leaderboard records . Because I only have three days , So I just wrote it 3 Days of
127.0.0.1:6379> zrevrange week:rank 0 -1 withscores
1) "post:1"
2) "30"
3) "post:2"
4) "15"
127.0.0.1:6379> The above record is correct . The above commands can help us simply realize our idea , Here's how to do it in code . There's a small one on it bug Is that when day:1 This day may appear, but it can't be over directly . May increase one by one , At this time, you should use the auto increment command to solve this problem .
# When +1 When -1 It's when you When you add a comment, add 1 When you delete, subtract 1
ZINCRBY day:1 10 post:1Code to implement
Current front end style , In this case, we need to start this function at the beginning of the project


@Component
// Realization Start class , also Contextual servlect
public class ContextStartup implements ApplicationRunner, ServletContextAware {
// Inject categoryService
@Autowired
IMCategoryService categoryService;
ServletContext servletContext;
// Inject post The service class
@Autowired
IMPostService postService;
@Override
public void run(ApplicationArguments args) throws Exception {
// Call the method of full query
List<MCategory> list = categoryService.list(new QueryWrapper<MCategory>().eq("status", 0));
servletContext.setAttribute("List", list);
// Call the method of weekly hot review
postService.initweek();
}
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
}Service serviceimpl class
General idea
obtain 7 Articles published within days
Initialize the total reading of the article
Cache the basic information of the article (id, title , comments , author ID )
In this way, we can avoid searching the database . You can use our cache directly .
Do Union
I need a Redis Tool class of , I found it on the Internet , I didn't write it . There's a lot of stuff on the Internet . Just use it directly
package com.example.springbootblog.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 java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtil {
@Autowired
private RedisTemplate redisTemplate;
/**
* Specify cache expiration time
*
* @param key key
* @param time Time ( second )
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* according to key Get expiration time
*
* @param key key Not for null
* @return Time ( second ) return 0 Stands for permanent validity
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* Judge key Whether there is
*
* @param key key
* @return true There is false non-existent
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Delete cache
*
* @param key You can pass a value Or more
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
//============================String=============================
/**
* Normal cache fetch
*
* @param key key
* @return value
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* Normal cache put in
*
* @param key key
* @param value value
* @return true success false Failure
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* The normal cache is put in and set the time
*
* @param key key
* @param value value
* @param time Time ( second ) time Be greater than 0 If time Less than or equal to 0 Will be set indefinitely
* @return true success false Failure
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Increasing
*
* @param key key
* @param delta How much more should I add ( Greater than 0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException(" The increment factor must be greater than 0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* Decline
*
* @param key key
* @param delta To cut it down a few ( Less than 0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException(" The decline factor must be greater than 0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
//================================Map=================================
/**
* HashGet
*
* @param key key Not for null
* @param item term Not for null
* @return value
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* obtain hashKey All the corresponding key values
*
* @param key key
* @return Corresponding multiple key values
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key key
* @param map Corresponding to multiple key values
* @return true success false Failure
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet And set the time
*
* @param key key
* @param map Corresponding to multiple key values
* @param time Time ( second )
* @return true success false Failure
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* To a piece of hash Put data in the table , If it doesn't exist, it will create
*
* @param key key
* @param item term
* @param value value
* @return true success false Failure
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* To a piece of hash Put data in the table , If it doesn't exist, it will create
*
* @param key key
* @param item term
* @param value value
* @param time Time ( second ) Be careful : If there is already hash Watch has time , This will replace the original time
* @return true success false Failure
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Delete hash The values in the table
*
* @param key key Not for null
* @param item term Can make multiple Not for null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* Judge hash Whether there is a value of this item in the table
*
* @param key key Not for null
* @param item term Not for null
* @return true There is false non-existent
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash Increasing If it doesn't exist , It creates a And return the added value to
*
* @param key key
* @param item term
* @param by How much more should I add ( Greater than 0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash Decline
*
* @param key key
* @param item term
* @param by Remember less ( Less than 0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
//============================set=============================
/**
* according to key obtain Set All the values in
*
* @param key key
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* according to value From a set Query in , Whether there is
*
* @param key key
* @param value value
* @return true There is false non-existent
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Put data into set cache
*
* @param key key
* @param values value It can be more than one
* @return The number of successes
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* take set Data is put into the cache
*
* @param key key
* @param time Time ( second )
* @param values value It can be more than one
* @return The number of successes
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) expire(key, time);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* obtain set The length of the cache
*
* @param key key
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* The removal value is value Of
*
* @param key key
* @param values value It can be more than one
* @return Number of removed
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
//===============================list=================================
/**
* obtain list The contents of the cache
*
* @param key key
* @param start Start
* @param end end 0 To -1 For all values
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* obtain list The length of the cache
*
* @param key key
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* Through the index obtain list The value in
*
* @param key key
* @param index Indexes index>=0 when , 0 Header ,1 The second element , By analogy ;index<0 when ,-1, Tail ,-2 The next to last element , By analogy
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* take list Put into cache
*
* @param key key
* @param value value
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* take list Put into cache
*
* @param key key
* @param value value
* @param time Time ( second )
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* take list Put into cache
*
* @param key key
* @param value value
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* take list Put into cache
*
* @param key key
* @param value value
* @param time Time ( second )
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Modify according to the index list A piece of data in
*
* @param key key
* @param index Indexes
* @param value value
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* remove N The values are value
*
* @param key key
* @param count How many removed
* @param value value
* @return Number of removed
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
//================ Ordered set sort set===================
/**
* Orderly set Additive elements
*
* @param key
* @param value
* @param score
* @return
*/
public boolean zSet(String key, Object value, double score) {
return redisTemplate.opsForZSet().add(key, value, score);
}
public long batchZSet(String key, Set<ZSetOperations.TypedTuple> typles) {
return redisTemplate.opsForZSet().add(key, typles);
}
public void zIncrementScore(String key, Object value, long delta) {
redisTemplate.opsForZSet().incrementScore(key, value, delta);
}
public void zUnionAndStore(String key, Collection otherKeys, String destKey) {
redisTemplate.opsForZSet().unionAndStore(key, otherKeys, destKey);
}
/**
* obtain zset Number
* @param key
* @param value
* @return
*/
public long getZsetScore(String key, Object value) {
Double score = redisTemplate.opsForZSet().score(key, value);
if(score==null){
return 0;
}else{
return score.longValue();
}
}
/**
* Get ordered set key Member of the member Ranking .
* The members of the ordered set press score The value is decreasing ( From big to small ) Sort .
* @param key
* @param start
* @param end
* @return
*/
public Set<ZSetOperations.TypedTuple> getZSetRank(String key, long start, long end) {
return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
}
}Code of implementation class
// The method of weekly hot review
@Override
public void initweek() {
// obtain 7 Day's article
List<MPost> posts = this.list(new QueryWrapper<MPost>().ge("created", DateUtil.lastWeek())
.select("id", "title", "user_id", "comment_count", "view_count", "created")
);// Get 7 Days ago and according to these queries , You don't need to query all
// Initialize the general comments of the article
for (MPost post : posts) {
// Set up key
String key = "day:rank:" + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);
// Number of comments cached
redisUtil.zSet(key, post.getId(), post.getCommentCount());
// Set auto expiration 7 Days overdue
long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
long expireTime = (7 - between) * 24 * 60 * 60; // It works Time
redisUtil.expire(key, expireTime);
// Cache some basic information of the article
this.hashCachePost(post, expireTime);
}
// Do Union
this.zunionAndStore();
}
/**
* The number of comments per week is combined
**/
private void zunionAndStore() {
String destkey = "day:rank:" + DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);
// Set new after union key
String newkey = "week:rank";
ArrayList<String> otherKeys = new ArrayList<>();
// Calculation 7 Days of
for (int i = -6; i < 0; i++) {
String temp = "day:rank:" + DateUtil.format(DateUtil.offsetDay(new Date(), i), DatePattern.PURE_DATE_FORMAT);
otherKeys.add(temp);
}
redisUtil.zUnionAndStore(destkey, otherKeys, newkey);
}
/**
* Article author
**/
private void hashCachePost(MPost post, long expireTime) {
// Set up key
String key = "rank:post:" + post.getId();
// Judge whether there is
boolean hasKey = redisUtil.hasKey(key);
if (!hasKey) {
// Just put it in the cache
redisUtil.hset(key, "post:id", post.getId(), expireTime);
redisUtil.hset(key, "post:title", post.getTitle(), expireTime);
redisUtil.hset(key, "post:commentCount", post.getCommentCount(), expireTime);
}
}
}In this way, we can convert our command line into code form . Then we can store the data of our database in the cache first .
effect
127.0.0.1:6379> keys *
1) "rank:post:4"
2) "week:rank"
3) "day:rank:20210724"
4) "rank:post:3"
5) "rank:post:2"
6) "day:rank:20210726"
# Look at the data after our union id by 3 There are 1 comments .
127.0.0.1:6379> zrevrange week:rank 0 -1 withscores
1) "3"
2) "1"
3) "2"
4) "1"
5) "4"
6) "0"
127.0.0.1:6379>In the database id by 3 There are 1 comments


There is really only one comment
The front end is displayed
The idea here is relatively simple , Just take our data out of the cache . With freemarker You can customize the label . I customized the label .
Hosttemplate
/**
* Hot discussion this week
*/
@Component
public class HotsTemplate extends TemplateDirective {
@Autowired
RedisUtil redisUtil;
@Override
public String getName() {
return "hots";
}
@Override
public void execute(DirectiveHandler handler) throws Exception {
// Set up key
String key ="week:rank";
Set<ZSetOperations.TypedTuple> zSetRank = redisUtil.getZSetRank(key, 0, 6);
ArrayList<Map> maps = new ArrayList<>();
// facilitate
for (ZSetOperations.TypedTuple typedTuple : zSetRank) {
// establish Map
HashMap<String, Object> map = new HashMap<>();
Object post_id = typedTuple.getValue();
String PostHashKey = "rank:post:" +post_id;
map.put("id",post_id);
map.put("title",redisUtil.hget(PostHashKey,"post:title"));
map.put("commentCount",typedTuple.getScore());
maps.add(map);
}
handler.put(RESULTS,maps).render();
}
} stay FreemarkerConfig We can use our custom tags by injecting the notes we wrote
@Configuration
public class FreemarkerConfig {
@Autowired
private freemarker.template.Configuration configuration;
@Autowired
PostsTemplate postsTemplate;
@Autowired
HotsTemplate hotsTemplate;
@PostConstruct
public void setUp() {
configuration.setSharedVariable("timeAgo", new TimeAgoMethod());
configuration.setSharedVariable("posts", postsTemplate);
configuration.setSharedVariable("hosts", hotsTemplate);
}
}Get the front page

effect

summary
When doing this function . Not comprehensive enough . Although it's finished , But it should be to get 7 Comments within days . I got 7 Day's article . Though it is a bug But I don't want to fix . be it so . Just use it now . It's the same thing . There will be time for problems. Let's change it . Tired , Ruthless code machines record code life .....
source :blog.csdn.net/m0_46937429/article/
details/119172118
recommend
Technical involution group , Learn together !!

PS: Because the official account platform changed the push rules. , If you don't want to miss the content , Remember to click after reading “ Looking at ”, Add one “ Star standard ”, In this way, each new article push will appear in your subscription list for the first time . spot “ Looking at ” Support us !
边栏推荐
- ImageView展示网络图片
- Using bindservice method to pause music playing
- I brush the question I - copy the linked list with random pointer
- Scala template method pattern
- 腾讯搬家了!
- bindservice方法实现音乐播放暂停
- 高考之后,必然会出现以下四种情况:
- 腾讯云WeCity丨产业联合 协同创新 共贺新春!
- 2022r1 quick opening pressure vessel operation test questions and answers
- 我想问一下兴业证券怎么开户?通过链接办理股票开户安全吗
猜你喜欢

Add information on the left and add parts on the right of the status bar

生成订单30分钟未支付,则自动取消,该怎么实现?

扎克伯格上手演示四款VR头显原型机,Meta透露元宇宙「家底」

粉丝福利,JVM 手册(包含 PDF)

1. 封装自己的脚手架 2.创建代码模块

Examination questions and mock examination for safety management personnel of hazardous chemical business units in 2022

4 ans d'expérience de travail, 5 modes de communication Multi - thread ne peuvent pas être décrits, vous osez croire?

Syntax highlighting of rich text

使用 Loki 微服务模式部署生产集群

Cobalt Strike安装教程
随机推荐
卷积与反卷积关系超详细说明及推导(反卷积又称转置卷积、分数步长卷积)
Text editor for QT project practice -- Episode 9
Scala sample class
ImageView展示网络图片
Lenovo tongfuyao: 11 times the general trend, we attacked the city and pulled out the stronghold all the way
mysql查询时间戳转换成日期格式
2022r1 quick opening pressure vessel operation test questions and answers
15.线程同步的几种方法
图片旋转移动缩放渐变
Bi SQL alias
图书馆管理系统代码源码(php+css+js+mysql) 完整的代码源码
Scala template method pattern
yasea apk 下载 镜像
Scala IO read by character
activity生命周期
云开发技术峰会·公益编程挑战赛【火热报名中】!
Danish Technical University pioneered the application of quantum computing to power flow modeling of energy system
Which securities company should I choose to open an account online? Is it safe to open an account online?
【直播回顾】2022腾讯云未来社区城市运营方招募会暨SaaS 2.0新品发布会!
I'd like to ask how to open an account at industrial securities? Is it safe to open a stock account through the link