SpringBoot+Redis Bitmap實現(xiàn)活躍用戶統(tǒng)計
前言
Redis的Bitmap數(shù)據(jù)結(jié)構(gòu)是一種緊湊的位圖,它可以用于實現(xiàn)各種場景,其中統(tǒng)計活躍用戶是一種經(jīng)典的業(yè)務(wù)場景。
實現(xiàn)原理是,通過將每個用戶表示為一個位,從而跟蹤用戶的活躍狀態(tài),使用位圖記錄用戶每天是否登錄,并計算月度或年度活躍用戶數(shù)。
案例代碼
以下是一個小例子,可以看到,使用SpringDataRedis,可以很輕松的實現(xiàn)BitMap的操作。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.BitSet; @Service public class UserLoginService { // 用戶登錄記錄的鍵前綴 private static final String LOGIN_KEY_PREFIX = "login:"; // 月份格式化器 private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM"); // 年份格式化器 private static final DateTimeFormatter YEAR_FORMATTER = DateTimeFormatter.ofPattern("yyyy"); @Autowired private RedisTemplate<String, Object> redisTemplate; /** * 記錄用戶登錄 * * @param userId 用戶ID */ public void recordLogin(String userId) { // 獲取存儲當(dāng)天用戶登錄信息的鍵 String loginKey = getLoginKey(); // 計算位圖偏移量,對應(yīng)用戶ID的哈希碼 int bitOffset = getUserIdHashCode(userId); // 將用戶ID對應(yīng)的位設(shè)置為1,表示用戶登錄 redisTemplate.opsForValue().setBit(loginKey, bitOffset, true); } /** * 獲取月度活躍用戶統(tǒng)計數(shù)據(jù) * * @return 月度活躍用戶統(tǒng)計數(shù)據(jù) */ public BitSet getMonthlyActiveUsers() { // 獲取存儲月度活躍用戶信息的鍵 String monthlyKey = getMonthlyKey(); // 從Redis中獲取位圖數(shù)據(jù) return retrieveBitSet(monthlyKey); } /** * 獲取年度活躍用戶統(tǒng)計數(shù)據(jù) * * @return 年度活躍用戶統(tǒng)計數(shù)據(jù) */ public BitSet getYearlyActiveUsers() { // 獲取存儲年度活躍用戶信息的鍵 String yearlyKey = getYearlyKey(); // 從Redis中獲取位圖數(shù)據(jù) return retrieveBitSet(yearlyKey); } /** * 獲取存儲當(dāng)天用戶登錄信息的鍵 */ private String getLoginKey() { LocalDate today = LocalDate.now(); String dateKey = today.format(DateTimeFormatter.ISO_DATE); return LOGIN_KEY_PREFIX + dateKey; } /** * 計算用戶ID的哈希碼,保證非負(fù)數(shù)并適應(yīng)位圖長度 */ private int getUserIdHashCode(String userId) { int hashCode = userId.hashCode(); // 1073741823是Redis位圖最大支持長度(2^30-1),可根據(jù)實際需求調(diào)整 return Math.abs(hashCode % 1073741823); } /** * 獲取存儲月度活躍用戶信息的鍵 */ private String getMonthlyKey() { LocalDate today = LocalDate.now(); String monthKey = today.format(MONTH_FORMATTER); return LOGIN_KEY_PREFIX + "monthly:" + monthKey; } /** * 獲取存儲年度活躍用戶信息的鍵 */ private String getYearlyKey() { LocalDate today = LocalDate.now(); String yearKey = today.format(YEAR_FORMATTER); return LOGIN_KEY_PREFIX + "yearly:" + yearKey; } /** * 從Redis中獲取位圖數(shù)據(jù) */ private BitSet retrieveBitSet(String key) { // 獲取存儲在Redis中的位圖數(shù)據(jù) byte[] bytes = (byte[]) redisTemplate.opsForValue().get(key); if (bytes != null) { // 將字節(jié)數(shù)組轉(zhuǎn)換為BitSet return BitSet.valueOf(bytes); } else { // 若不存在,則返回空的BitSet return new BitSet(); } } }
其中有幾個地方解釋一下:
1、recordLogin方法用于記錄用戶登錄情況。每天的登錄情況被保存在以"login:日期"為鍵的位圖中,用戶的登錄狀態(tài)由位圖中對應(yīng)的位表示;
2、countMonthlyActiveUsers方法用于計算月度活躍用戶數(shù)量。每個月的活躍用戶數(shù)保存在以"login:monthly:年月"為鍵的位圖中,通過Redis的bitCount方法統(tǒng)計位圖中置為1的位數(shù),即月度活躍用戶數(shù);
3、ountYearlyActiveUsers方法用于計算年度活躍用戶數(shù)量,原理同上,只是統(tǒng)計的鍵變?yōu)?quot;login:yearly:年份";
4、getLoginKey、getUserIdHashCode、getMonthlyKey和getYearlyKey是輔助方法,負(fù)責(zé)生成對應(yīng)的Redis鍵或計算用戶ID的哈希碼。
轉(zhuǎn)換
上面的例子最終返回的是BitSet對象,通過這個對象我們經(jīng)過轉(zhuǎn)換后可以獲取到許多經(jīng)典的統(tǒng)計數(shù)據(jù),這里列舉一些經(jīng)典常用的統(tǒng)計結(jié)果示例。
大家可以根據(jù)這里面列舉的統(tǒng)計數(shù)據(jù),針對上面的代碼進行替換,得到自己想要的結(jié)果。
import java.util.BitSet; // 獲取月度活躍用戶統(tǒng)計數(shù)據(jù) BitSet monthlyActiveUsers = userLoginService.getMonthlyActiveUsers(); // 獲取年度活躍用戶統(tǒng)計數(shù)據(jù) BitSet yearlyActiveUsers = userLoginService.getYearlyActiveUsers(); // 統(tǒng)計月度活躍用戶數(shù)量 int monthlyActiveUserCount = monthlyActiveUsers.cardinality(); // 統(tǒng)計年度活躍用戶數(shù)量 int yearlyActiveUserCount = yearlyActiveUsers.cardinality(); // 判斷某個用戶是否為月度活躍用戶 String userId = "user123"; boolean isMonthlyActiveUser = monthlyActiveUsers.get(userLoginService.getUserIdHashCode(userId)); // 判斷某個用戶是否為年度活躍用戶 boolean isYearlyActiveUser = yearlyActiveUsers.get(userLoginService.getUserIdHashCode(userId)); // 輸出統(tǒng)計結(jié)果 System.out.println("月度活躍用戶數(shù)量: " + monthlyActiveUserCount); System.out.println("年度活躍用戶數(shù)量: " + yearlyActiveUserCount); System.out.println("用戶user123是否為月度活躍用戶: " + isMonthlyActiveUser); System.out.println("用戶user123是否為年度活躍用戶: " + isYearlyActiveUser);
總結(jié)
Redis的Bitmap數(shù)據(jù)結(jié)構(gòu)非常靈活,可以根據(jù)具體需求實現(xiàn)各種位操作,但平時在項目中很多人沒有機會使用到,這個案例非常簡單,希望能讓大家對此有個認(rèn)識,未來用到了不會感到陌生。
以上就是SpringBoot+Redis Bitmap實現(xiàn)活躍用戶統(tǒng)計的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Redis Bitmap用戶統(tǒng)計的資料請關(guān)注腳本之家其它相關(guān)文章!
- springboot項目Redis統(tǒng)計在線用戶的實現(xiàn)示例
- SpringBoot+Redis?BitMap實現(xiàn)簽到與統(tǒng)計的項目實踐
- 微服務(wù)Spring Boot 整合 Redis 實現(xiàn)UV 數(shù)據(jù)統(tǒng)計的詳細(xì)過程
- 微服務(wù)?Spring?Boot?整合?Redis?BitMap?實現(xiàn)?簽到與統(tǒng)計功能
- SpringBoot整合Redis實現(xiàn)訪問量統(tǒng)計的示例代碼
- SpringBoot使用Redis的zset統(tǒng)計在線用戶信息
- SpringBoot運用Redis統(tǒng)計用戶在線數(shù)量的兩種方法實現(xiàn)
相關(guān)文章
通過實例了解java checked和unchecked異常
這篇文章主要介紹了通過實例了解checked和unchecked異常,Java異常分為兩種類型,checked異常和unchecked異常,另一種叫法是異常和錯誤。下面小編就帶大家來一起學(xué)習(xí)一下吧2019-06-06通過java記錄數(shù)據(jù)持續(xù)變化時間代碼解析
這篇文章主要介紹了通過java記錄數(shù)據(jù)持續(xù)變化時間代碼解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01Java中的ReentrantLock、ReentrantReadWriteLock、StampedLock詳解
這篇文章主要介紹了Java中的ReentrantLock、ReentrantReadWriteLock、StampedLock詳解,讀寫鎖:一個資源能夠被多個讀線程訪問,或者被一個寫線程訪問但是不能同時存在讀寫線程,需要的朋友可以參考下2024-01-01