当前位置:网站首页>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 !
边栏推荐
- 2022 simulated 100 questions of safety officer-c certificate examination and online simulated examination
- 2022年起重机司机(限桥式起重机)考试题库模拟考试平台操作
- Cobalt strike installation tutorial
- Scala sample object
- 腾讯完成全面上云 打造国内最大云原生实践
- 汇编语言(2)基础知识-debug
- Text editor for QT project practice -- Episode 9
- Zuckerberg demonstrated four VR head display prototypes, and meta revealed the "family" of metauniverse
- 108页(4万字)未来公寓智能化设计平台项目方案建议书2022版
- 中金财富证券开户佣金多少呢?股票开户交易安全靠谱吗?
猜你喜欢

Deep learning LSTM model for stock analysis and prediction

4年工作经验,多线程间的5种通信方式都说不出来,你敢信?

Bi-sql between

JS Chapter 1 Summary

Cobalt strike installation tutorial

51单片机多机通信

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

I brush the question I - copy the linked list with random pointer

Introduction to bi-sql wildcards

图书馆管理系统代码源码(php+css+js+mysql) 完整的代码源码
随机推荐
扎克伯格上手演示四款VR头显原型机,Meta透露元宇宙「家底」
How to store dataframe data in pandas into MySQL
Activity lifecycle
Bi SQL alias
yasea apk 下载 镜像
Go language operators (under Lesson 8)
2022安全员-C证考试模拟100题及在线模拟考试
Which securities company should I choose to open an account online? Is it safe to open an account online?
This national day! Tencent cloud wecity will accompany you to travel and light up the city landmark
4 years of working experience, and you can't tell the five communication modes between multithreads. Can you believe it?
Scala sample class case calculate
2022年全国最新消防设施操作员(高级消防设施操作员)模拟题及答案
Scala responsibility chain pattern
Scala adapter pattern
Convolution and transpose convolution
Scala object blending trait
改造一下 BeanUtils,优雅的实现 List 数据拷贝
【无标题】
纹理增强
Scala trait construction mechanism