Java使用Redis實現(xiàn)微博熱搜功能
介紹
在社交平臺上,熱搜功能是一個非常重要的組成部分。它展示了當前最熱門的話題,幫助用戶迅速了解最受關(guān)注的事件。在微博等平臺上,熱搜榜單通常是實時變化的,可能會根據(jù)用戶的互動數(shù)據(jù)(如搜索頻次、點贊量、評論數(shù)等)動態(tài)調(diào)整。
Redis 是一個高性能的鍵值存儲系統(tǒng),通常用于緩存和實時數(shù)據(jù)存儲,特別適用于實現(xiàn)類似熱搜榜單這樣的功能。本文將通過 Java 結(jié)合 Redis 實現(xiàn)一個簡化版的微博熱搜功能,展示如何使用 Redis 提供的高效數(shù)據(jù)結(jié)構(gòu),如 SortedSet(有序集合)來維護熱搜榜單。

熱度的計算方式,不同的產(chǎn)品的熱度計算方式不同:
例如:
熱度=評論數(shù)+轉(zhuǎn)發(fā)數(shù)+點贊數(shù)
熱度=搜索量+點擊量
熱搜排行榜可以分為:當前小時的熱搜榜,當天的熱搜榜,當月的熱搜榜,當前周的熱搜榜等等。
思路: 一般情況下,我們按照存儲每個小時的小時榜,為最小單位。 同理,當天的熱搜榜,就是這一天24小時的小時榜合并后的榜單。當月的熱搜榜就是,這個月每天的熱搜榜合并后的榜單。
1. Redis 數(shù)據(jù)結(jié)構(gòu)介紹
在實現(xiàn)熱搜功能時,Redis 提供的 SortedSet(有序集合)是非常合適的。SortedSet 會根據(jù)分數(shù)(score)對成員(member)進行排序,適用于我們要根據(jù)熱度(例如搜索頻次、點贊數(shù)等)排序展示的場景。
- SortedSet(zset):是一個有序的集合,每個元素都有一個分數(shù)(score),Redis 會自動根據(jù)分數(shù)對元素進行排序。適合實現(xiàn)需要排序的場景,如熱搜榜單、排行榜等。
2.當前小時的key的設(shè)定思路:
1.使用當前的時間戳來生成唯一的 key,通常使用 YYYY-MM-DD-HH 作為 key 的格式,這樣每天每小時的數(shù)據(jù)都會有獨立的 key。
例如:當前時間為 2024-12-10 07:25:21,那么對應(yīng)的 key 為 2024-12-10-07。
2.當前時間的毫秒的時間(T),當前小時唯一key=T/1000*60*60;
例如:當前時間為2024-12-10 16:10:40=1733818240000 ,那么對應(yīng)的key就是:1733818240000 /1000*60*60=481,616
以上兩種方式,都可以獲取到當前時間的唯一的key。
3.代碼實現(xiàn)
1. 引入依賴
在你的 pom.xml 中加入以下依賴來使用 Redis 和 Jedis:
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.2.3</version>
</dependency>
</dependencies>主要需要實現(xiàn)的功能:熱搜的小時榜,天榜,月榜的榜單的實現(xiàn)。
首先編寫redis的基本操作的工具類:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Set;
public class RedisUtil {
private static JedisPool pool;
static {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(50);
config.setMaxIdle(10);
config.setMinIdle(5);
config.setTestOnBorrow(true);
pool = new JedisPool(config, "localhost", 6379); // Redis 地址
}
public static Jedis getJedis() {
return pool.getResource();
}
public static void close(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
public static void incrementSearchCount(String key,String topic) {
Jedis jedis = getJedis();
try {
// 使用 Redis 的 ZINCRBY 命令遞增話題的熱度
jedis.zincrby(key, 1, topic);
} finally {
close(jedis);
}
}
public static Set<String> getTopSearch(int topN) {
Jedis jedis = getJedis();
try {
// 使用 Redis 的 ZREVRANGE 命令獲取熱搜榜單
return jedis.zrevrange("hot_search", 0, topN - 1);
} finally {
close(jedis);
}
}
}熱搜的增加,每次都是單個增加的,此處不做解釋。我們主要研究,如何查詢,小時榜,天榜,月榜的數(shù)據(jù)。
具體代碼如下:
@Autowired
private RedisTemplate redisTemplate;
/**
* 更新天的熱搜數(shù)據(jù)
*/
public void updateDaySearch(){
long hour = System.currentTimeMillis()/(1000*60*60);
//小時key的前綴
String hourPrefix = "search:hour";
//天的key
String dayPrefix = "search:day";
//計算最近24小時的key的集合
ArrayList<Object> dayKeys = new ArrayList<>();
//統(tǒng)計近24小時的key的集合
for (int i = 1; i < 23; i++) {
String key = hourPrefix+(hour-i);
dayKeys.add(key);
//設(shè)置當天的key 40天過期,防止資源的浪費
redisTemplate.expire(key,40, TimeUnit.DAYS);
}
//將近24小時的key的值進行合并
//(redisTemplate.opsForZSet()。unionAndStore(a,b,c);把a,b 兩個zset合并儲存到c集合中)
redisTemplate.opsForZSet().unionAndStore(hourPrefix+hour,dayKeys,dayPrefix);
log.info("*********************進行天數(shù)據(jù)的更新************************");
}
public void updateMonthSearch(){
long hour = System.currentTimeMillis()/(1000*60*60);
//小時key的前綴
String hourPrefix = "search:hour";
//天的key
String monthPrefix = "search:day";
//計算最近24小時的key的集合
ArrayList<Object> monthKeys = new ArrayList<>();
//統(tǒng)計近24小時的key的集合
for (int i = 1; i < 24*30-1; i++) {
String key = hourPrefix+(hour-i);
monthKeys.add(key);
}
//將近30天的key的值進行合并
redisTemplate.opsForZSet().unionAndStore(hourPrefix+hour,monthKeys,monthPrefix);
log.info("***************進行月數(shù)據(jù)的更新*********************");
}
/**
* 更新最近7天的數(shù)據(jù)
*/
public void updateWeekSearch(){
long hour = System.currentTimeMillis()/(1000*60*60);
//小時key的前綴
String hourPrefix = "search:hour";
//周的key
String weekPrefix = "search:week";
//計算最近24小時的key的集合
ArrayList<Object> weekKeys = new ArrayList<>();
//統(tǒng)計近24小時的key的集合
for (int i = 1; i < 24*7-1; i++) {
String key = hourPrefix+(hour-i);
weekKeys.add(key);
}
//將近30天的key的值進行合并
redisTemplate.opsForZSet().unionAndStore(hourPrefix+hour,weekKeys,weekPrefix);
log.info("************進行周數(shù)據(jù)的更新******************");
}
/**
* 定時器每小時調(diào)用一次次方法進行,小時榜,天榜,周榜,月榜的更新
*/
public void updateAllSearch(){
//TODO 此方法建議使用定時框架,quartz ,xxl-job等進行定時調(diào)用
updateDaySearch();
updateWeekSearch();
updateMonthSearch();
}4. 優(yōu)化和擴展
- 熱搜榜單過期策略:可以設(shè)置 Redis 中有序集合的過期時間,定期清理不再熱門的關(guān)鍵詞。
- 多維度排序:除了搜索次數(shù)外,可以根據(jù)時間窗口(例如過去一小時、一天內(nèi)的搜索量)來做更加復(fù)雜的排序。
- 高并發(fā)優(yōu)化:為了避免頻繁的 Redis 操作影響性能,可以考慮將熱搜數(shù)據(jù)批量更新或者使用消息隊列來異步處理。
總結(jié)
通過以上的實現(xiàn),我們展示了如何使用 Java 和 Redis 來實現(xiàn)一個簡單的微博熱搜功能。通過 Redis 的有序集合,我們能夠高效地記錄和排序搜索關(guān)鍵詞的熱度,并在用戶請求時實時返回當前最熱門的話題。
這種基于 Redis 的熱搜功能不僅適用于微博,實際上可以廣泛應(yīng)用于各種需要統(tǒng)計熱門話題或關(guān)鍵詞的場景,如新聞網(wǎng)站、視頻平臺等。
以上就是Java使用Redis實現(xiàn)微博熱搜功能的詳細內(nèi)容,更多關(guān)于Java Redis微博熱搜的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
修改jar包package目錄結(jié)構(gòu)操作方法
這篇文章主要介紹了修改jar包package目錄結(jié)構(gòu)操作方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下2019-07-07
Spring Boot使用過濾器和攔截器分別實現(xiàn)REST接口簡易安全認證示例代碼詳解
這篇文章主要介紹了Spring Boot使用過濾器和攔截器分別實現(xiàn)REST接口簡易安全認證示例代碼,通過開發(fā)實踐,理解過濾器和攔截器的工作原理,需要的朋友可以參考下2018-06-06
Java執(zhí)行SQL腳本文件到數(shù)據(jù)庫詳解
這篇文章主要為大家詳細介紹了Java執(zhí)行SQL腳本文件到數(shù)據(jù)庫的相關(guān)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06
快速校驗實體類時,@Valid,@Validated,@NotNull注解無效的解決
這篇文章主要介紹了快速校驗實體類時,@Valid,@Validated,@NotNull注解無效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10

