亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot+Redis Bitmap實(shí)現(xiàn)活躍用戶(hù)統(tǒng)計(jì)

 更新時(shí)間:2023年11月17日 10:40:25   作者:myprince003  
Redis的Bitmap數(shù)據(jù)結(jié)構(gòu)是一種緊湊的位圖,它可以用于實(shí)現(xiàn)各種場(chǎng)景,其中統(tǒng)計(jì)活躍用戶(hù)是一種經(jīng)典的業(yè)務(wù)場(chǎng)景,下面我們就來(lái)學(xué)習(xí)一下SpringBoot如何利用Redis中的Bitmap實(shí)現(xiàn)活躍用戶(hù)統(tǒng)計(jì)吧

前言

Redis的Bitmap數(shù)據(jù)結(jié)構(gòu)是一種緊湊的位圖,它可以用于實(shí)現(xiàn)各種場(chǎng)景,其中統(tǒng)計(jì)活躍用戶(hù)是一種經(jīng)典的業(yè)務(wù)場(chǎng)景。

實(shí)現(xiàn)原理是,通過(guò)將每個(gè)用戶(hù)表示為一個(gè)位,從而跟蹤用戶(hù)的活躍狀態(tài),使用位圖記錄用戶(hù)每天是否登錄,并計(jì)算月度或年度活躍用戶(hù)數(shù)。

案例代碼

以下是一個(gè)小例子,可以看到,使用SpringDataRedis,可以很輕松的實(shí)現(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 {

    // 用戶(hù)登錄記錄的鍵前綴
    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;

    /**
     * 記錄用戶(hù)登錄
     *
     * @param userId 用戶(hù)ID
     */
    public void recordLogin(String userId) {

        // 獲取存儲(chǔ)當(dāng)天用戶(hù)登錄信息的鍵
        String loginKey = getLoginKey(); 
        // 計(jì)算位圖偏移量,對(duì)應(yīng)用戶(hù)ID的哈希碼
        int bitOffset = getUserIdHashCode(userId); 
        // 將用戶(hù)ID對(duì)應(yīng)的位設(shè)置為1,表示用戶(hù)登錄
        redisTemplate.opsForValue().setBit(loginKey, bitOffset, true); 
    }

    /**
     * 獲取月度活躍用戶(hù)統(tǒng)計(jì)數(shù)據(jù)
     *
     * @return 月度活躍用戶(hù)統(tǒng)計(jì)數(shù)據(jù)
     */
    public BitSet getMonthlyActiveUsers() {

        // 獲取存儲(chǔ)月度活躍用戶(hù)信息的鍵
        String monthlyKey = getMonthlyKey(); 
        // 從Redis中獲取位圖數(shù)據(jù)
        return retrieveBitSet(monthlyKey); 
    }

    /**
     * 獲取年度活躍用戶(hù)統(tǒng)計(jì)數(shù)據(jù)
     *
     * @return 年度活躍用戶(hù)統(tǒng)計(jì)數(shù)據(jù)
     */
    public BitSet getYearlyActiveUsers() {

        // 獲取存儲(chǔ)年度活躍用戶(hù)信息的鍵
        String yearlyKey = getYearlyKey(); 
        // 從Redis中獲取位圖數(shù)據(jù)
        return retrieveBitSet(yearlyKey); 
    }

    /**
     * 獲取存儲(chǔ)當(dāng)天用戶(hù)登錄信息的鍵
     */
    private String getLoginKey() {

        LocalDate today = LocalDate.now();
        String dateKey = today.format(DateTimeFormatter.ISO_DATE);
        return LOGIN_KEY_PREFIX + dateKey;
    }

    /**
     * 計(jì)算用戶(hù)ID的哈希碼,保證非負(fù)數(shù)并適應(yīng)位圖長(zhǎng)度
     */
    private int getUserIdHashCode(String userId) {

        int hashCode = userId.hashCode();
        // 1073741823是Redis位圖最大支持長(zhǎng)度(2^30-1),可根據(jù)實(shí)際需求調(diào)整
        return Math.abs(hashCode % 1073741823); 
    }

    /**
     * 獲取存儲(chǔ)月度活躍用戶(hù)信息的鍵
     */
    private String getMonthlyKey() {

        LocalDate today = LocalDate.now();
        String monthKey = today.format(MONTH_FORMATTER);
        return LOGIN_KEY_PREFIX + "monthly:" + monthKey;
    }

    /**
     * 獲取存儲(chǔ)年度活躍用戶(hù)信息的鍵
     */
    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) {

        // 獲取存儲(chǔ)在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(); 
        }
    }
}

其中有幾個(gè)地方解釋一下:

1、recordLogin方法用于記錄用戶(hù)登錄情況。每天的登錄情況被保存在以"login:日期"為鍵的位圖中,用戶(hù)的登錄狀態(tài)由位圖中對(duì)應(yīng)的位表示;

2、countMonthlyActiveUsers方法用于計(jì)算月度活躍用戶(hù)數(shù)量。每個(gè)月的活躍用戶(hù)數(shù)保存在以"login:monthly:年月"為鍵的位圖中,通過(guò)Redis的bitCount方法統(tǒng)計(jì)位圖中置為1的位數(shù),即月度活躍用戶(hù)數(shù);

3、ountYearlyActiveUsers方法用于計(jì)算年度活躍用戶(hù)數(shù)量,原理同上,只是統(tǒng)計(jì)的鍵變?yōu)?quot;login:yearly:年份";

4、getLoginKey、getUserIdHashCode、getMonthlyKey和getYearlyKey是輔助方法,負(fù)責(zé)生成對(duì)應(yīng)的Redis鍵或計(jì)算用戶(hù)ID的哈希碼。

轉(zhuǎn)換

上面的例子最終返回的是BitSet對(duì)象,通過(guò)這個(gè)對(duì)象我們經(jīng)過(guò)轉(zhuǎn)換后可以獲取到許多經(jīng)典的統(tǒng)計(jì)數(shù)據(jù),這里列舉一些經(jīng)典常用的統(tǒng)計(jì)結(jié)果示例。

大家可以根據(jù)這里面列舉的統(tǒng)計(jì)數(shù)據(jù),針對(duì)上面的代碼進(jìn)行替換,得到自己想要的結(jié)果。

import java.util.BitSet;

// 獲取月度活躍用戶(hù)統(tǒng)計(jì)數(shù)據(jù)
BitSet monthlyActiveUsers = userLoginService.getMonthlyActiveUsers();

// 獲取年度活躍用戶(hù)統(tǒng)計(jì)數(shù)據(jù)
BitSet yearlyActiveUsers = userLoginService.getYearlyActiveUsers();

// 統(tǒng)計(jì)月度活躍用戶(hù)數(shù)量
int monthlyActiveUserCount = monthlyActiveUsers.cardinality();

// 統(tǒng)計(jì)年度活躍用戶(hù)數(shù)量
int yearlyActiveUserCount = yearlyActiveUsers.cardinality();

// 判斷某個(gè)用戶(hù)是否為月度活躍用戶(hù)
String userId = "user123";
boolean isMonthlyActiveUser = monthlyActiveUsers.get(userLoginService.getUserIdHashCode(userId));

// 判斷某個(gè)用戶(hù)是否為年度活躍用戶(hù)
boolean isYearlyActiveUser = yearlyActiveUsers.get(userLoginService.getUserIdHashCode(userId));

// 輸出統(tǒng)計(jì)結(jié)果
System.out.println("月度活躍用戶(hù)數(shù)量: " + monthlyActiveUserCount);
System.out.println("年度活躍用戶(hù)數(shù)量: " + yearlyActiveUserCount);
System.out.println("用戶(hù)user123是否為月度活躍用戶(hù): " + isMonthlyActiveUser);
System.out.println("用戶(hù)user123是否為年度活躍用戶(hù): " + isYearlyActiveUser);

總結(jié)

Redis的Bitmap數(shù)據(jù)結(jié)構(gòu)非常靈活,可以根據(jù)具體需求實(shí)現(xiàn)各種位操作,但平時(shí)在項(xiàng)目中很多人沒(méi)有機(jī)會(huì)使用到,這個(gè)案例非常簡(jiǎn)單,希望能讓大家對(duì)此有個(gè)認(rèn)識(shí),未來(lái)用到了不會(huì)感到陌生。

以上就是SpringBoot+Redis Bitmap實(shí)現(xiàn)活躍用戶(hù)統(tǒng)計(jì)的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Redis Bitmap用戶(hù)統(tǒng)計(jì)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java Proxy機(jī)制詳細(xì)解讀

    Java Proxy機(jī)制詳細(xì)解讀

    這篇文章主要介紹了Java Proxy機(jī)制詳細(xì)解讀,還是非常不錯(cuò)的,這里分享給大家,需要的朋友可以參考下。
    2017-10-10
  • 通過(guò)實(shí)例了解java checked和unchecked異常

    通過(guò)實(shí)例了解java checked和unchecked異常

    這篇文章主要介紹了通過(guò)實(shí)例了解checked和unchecked異常,Java異常分為兩種類(lèi)型,checked異常和unchecked異常,另一種叫法是異常和錯(cuò)誤。下面小編就帶大家來(lái)一起學(xué)習(xí)一下吧
    2019-06-06
  • Java中可變長(zhǎng)度參數(shù)代碼詳解

    Java中可變長(zhǎng)度參數(shù)代碼詳解

    這篇文章主要介紹了Java中可變長(zhǎng)度參數(shù)代碼詳解,涉及了實(shí)參個(gè)數(shù)可變的定義方法,數(shù)組包裹實(shí)參等幾個(gè)問(wèn)題,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-12-12
  • java實(shí)現(xiàn)微信支付結(jié)果通知

    java實(shí)現(xiàn)微信支付結(jié)果通知

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)微信支付結(jié)果通知,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • springboot自動(dòng)裝配原理初識(shí)

    springboot自動(dòng)裝配原理初識(shí)

    這篇文章主要介紹了springboot自動(dòng)裝配原理的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用springboot,感興趣的朋友可以了解下
    2021-04-04
  • Java中的List接口實(shí)現(xiàn)類(lèi)解析

    Java中的List接口實(shí)現(xiàn)類(lèi)解析

    這篇文章主要介紹了Java中的List接口實(shí)現(xiàn)類(lèi)解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 通過(guò)java記錄數(shù)據(jù)持續(xù)變化時(shí)間代碼解析

    通過(guò)java記錄數(shù)據(jù)持續(xù)變化時(shí)間代碼解析

    這篇文章主要介紹了通過(guò)java記錄數(shù)據(jù)持續(xù)變化時(shí)間代碼解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • 淺談為什么Java里面String類(lèi)是不可變的

    淺談為什么Java里面String類(lèi)是不可變的

    這篇文章主要介紹了為什么Java里面String類(lèi)是不可變的,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • springboot項(xiàng)目如何使用切面記錄用戶(hù)操作日志

    springboot項(xiàng)目如何使用切面記錄用戶(hù)操作日志

    這篇文章主要介紹了springboot項(xiàng)目如何使用切面記錄用戶(hù)操作日志,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Java中的ReentrantLock、ReentrantReadWriteLock、StampedLock詳解

    Java中的ReentrantLock、ReentrantReadWriteLock、StampedLock詳解

    這篇文章主要介紹了Java中的ReentrantLock、ReentrantReadWriteLock、StampedLock詳解,讀寫(xiě)鎖:一個(gè)資源能夠被多個(gè)讀線(xiàn)程訪(fǎng)問(wèn),或者被一個(gè)寫(xiě)線(xiàn)程訪(fǎng)問(wèn)但是不能同時(shí)存在讀寫(xiě)線(xiàn)程,需要的朋友可以參考下
    2024-01-01

最新評(píng)論