BloomFilter如何快速檢查用戶名重復(fù)
背景
在我們的項目中,用戶名是不能重復(fù)的,因為在數(shù)藏項目中,用戶名的唯一性很重要,因為藏品要做溯源,要確保整個鏈路上的參與者的唯一性,雖然用戶 id 也是我唯一的,但是頁面上展示的時候不能用 id 呀。
有些網(wǎng)站,比如淘寶網(wǎng),也是要求用戶名唯一的。
所以為了實現(xiàn)這個用戶在注冊,改名的時候的用戶名的唯一性,我們一般是先從數(shù)據(jù)庫查詢是否存在,不存在則讓用戶注冊。
但是為了考慮到性能,我們會把用戶名存儲到緩存中,一般使用 redis 緩存。
那既然都用了緩存了,那還不如干脆直接就用布隆過濾器來存儲,既可以做重復(fù)校驗,又能節(jié)省空間。所以,我們在用戶名重復(fù)檢驗這里就用到了布隆過濾器。
簡介
布隆過濾器是一種數(shù)據(jù)結(jié)構(gòu),用于快速檢索一個元素是否可能存在于一個集合(bit 數(shù)組)中。
它的基本原理是利用多個哈希函數(shù),將一個元素映射成多個位,然后將這些位設(shè)置為 1。當查詢一個元素時,如果這些位都被設(shè)置為 1,則認為元素可能存在于集合中,否則肯定不存在。
所以,布隆過濾器可以準確的判斷一個元素是否一定不存在,但是因為哈希沖突的存在,所以他沒辦法判斷一個元素一定存在。只能判斷可能存在。
代碼實現(xiàn)
所以,我們定義了兩個方法,nickNameExist用于判斷是否存在,addNickName用于向布隆過濾器中添加已注冊的用戶名。
public boolean nickNameExist(String nickName) { //如果布隆過濾器中存在,再進行數(shù)據(jù)庫二次判斷 if (this.bloomFilter.contains(nickName)) { return userMapper.findByNickname(nickName) != null; } return false; } private boolean addNickName(String nickName) { return this.bloomFilter.add(nickName); }
這里nickNameExist方法,先從布隆過濾器中查詢,如果如果查到了,再去數(shù)據(jù)庫中查了一下,為啥呢?
因為布隆過濾器有誤判的,存在一定的誤判率,他會把不存在的用戶判斷為存在,所以當檢查結(jié)果是存在的時候,需要再次判斷一次。
因為用戶注冊的時候,大多數(shù)情況下都是不重復(fù)的,所以我們可以快速的用布隆過濾器進行不存在的判斷。
這里的bloomFilter是這樣被初始化出來的:
private RBloomFilter<String> bloomFilter; @Override public void afterPropertiesSet() throws Exception { this.bloomFilter = redissonClient.getBloomFilter("nickName"); if (!bloomFilter.isExists()) { this.bloomFilter.tryInit(10000000L, 0.01); } }
我們設(shè)置了10000000的容量,誤判率是0.01。
然后在修改用戶名這里,用這樣的方式進行調(diào)用的。
如果用戶名修改了怎么辦?
如果原來用戶名是Aizer,被放到布隆過濾器了,但是后面我改成 Aizer666了,那么意味著 Aizer已經(jīng)沒有了,那么如何從布隆過濾器刪除呢?
很遺憾,不支持!
那怎么辦呢?
其實問題也不大,因為布隆過濾器本身就存在誤判率,但我們檢查布隆過濾器發(fā)現(xiàn)存在的時候,還是會去數(shù)據(jù)庫再確認一遍的。
只要我們定期的重建一下布隆過濾器就行了。重建就是都刪了,然后重新構(gòu)建。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java中ScheduledExecutorService介紹和使用案例(推薦)
ScheduledExecutorService是Java并發(fā)包中的接口,用于安排任務(wù)在給定延遲后運行或定期執(zhí)行,它繼承自ExecutorService,具有線程池特性,可復(fù)用線程,提高效率,本文主要介紹java中的ScheduledExecutorService介紹和使用案例,感興趣的朋友一起看看吧2024-10-10spring batch 讀取多個文件數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫示例
本篇文章主要介紹了spring batch 讀取多個文件數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-03-03java 設(shè)計模式之State(狀態(tài)模式)
這篇文章主要介紹了java 設(shè)計模式之State(狀態(tài)模式)的相關(guān)資料,一個類的行為基于它的狀態(tài)的改變而改變。狀態(tài)模式歸屬于行為型模式,需要的朋友可以參考下2017-08-08教你開發(fā)腳手架集成Spring?Boot?Actuator監(jiān)控的詳細過程
這篇文章主要介紹了開發(fā)腳手架集成Spring?Boot?Actuator監(jiān)控的詳細過程,集成包括引入依賴配置文件及訪問驗證的相關(guān)知識,本文給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05解決異常處理問題:getReader()?has?already?been?called?for?this
這篇文章主要介紹了解決異常處理:getReader()?has?already?been?called?for?this問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01Java實現(xiàn)批量查找與替換Excel文本的思路詳解
在 Java 中,可以通過find和replace的方法來查找和替換單元格的數(shù)據(jù),下面小編將以Excel文件為例為大家介紹如何實現(xiàn)Excel文件內(nèi)容的批量替換,感興趣的朋友跟隨小編一起看看吧2023-10-10java如何實現(xiàn)項目啟動時執(zhí)行指定方法
這篇文章主要為大家詳細介紹了java項目如何啟動時執(zhí)行指定方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07