Redis bitmaps

認真寫文章,用心作分享。java

我的網站:yasinshaw.com面試

公衆號:xy的技術圈算法

前面的文章介紹了Redis的五種最經常使用的對象及其底層的數據結構。這篇文章主要介紹一下一個不那麼經常使用,卻很是適用於一些特殊場景的對象:bitmaps。數據庫

面臨的問題

先考慮幾個常見的場景:編程

  • 查詢今天登錄的用戶數量
  • 查詢今天有哪些用戶登陸了
  • 查詢某個用戶是否點贊過某篇文章
  • 查詢某個用戶是否連續兩天都登錄
  • 查詢點贊過文章A且點贊過文章B的用戶

這些需求可使用數據庫來實現,使用一些日誌表,再經過SQL查詢出來。但這樣會浪費大量的磁盤空間,並且性能還很低。在數據量比較大的狀況下,使用數據庫來查詢分析會很是慢。數組

這裏要感謝咱們計算機的科學家大佬們,發明了一種數據結構能夠用來解決這類問題。它就是BitMap。也就是這篇文章主要介紹的Redis bitmaps底層使用的數據結構。數據結構

《編程珠璣》中第一篇講的就是使用BitMap來排序大文件裏面的數據。在一些面試裏也會有相似的題目。性能

面試題目:一個10G的文件,裏面所有是天然數,一行一個,亂序排列,對其排序。在32位機器上面完成,內存限制爲2G。網站

LeetCode上有一個算法題,也是可使用BitMap來解決:日誌

算法題目:從0到n之間取出n個不一樣的數,找出漏掉的那個。注意:你的算法應當具備線性的時間複雜度。你能實現只佔用常數額外空間複雜度的算法嗎?

BitMap原理

BitMap實際上是一個數據結構,它是利用了位運算的高性能,來存儲和計算一些信息。接下來咱們來介紹一下BitMap的原理。

BitMap是基於bit位的位置來記錄信息的。好比咱們如今有一個8位的BitMap。最開始時,全部位上都是0。

0, 0, 0, 0, 0, 0, 0, 0

而後有這麼一個需求:假設今天有id爲1,2,4,7這四個用戶登陸了咱們的系統,咱們想要把這個登陸信息記錄下來,就只須要在相應的位置標記爲1就好了:

1, 1, 0, 1, 0, 0, 1, 0

這個時候,你想知道id爲7的用戶今天是否登陸過系統,就只須要去看這個BitMap裏面第7位是否是1就能夠了。

能夠看到,若是你使用一個list或者set來存的話,若是一個id是一個byte,佔8位(真實狀況多是long類型,佔64位),那8個id就要佔64位,而使用BitMap只須要佔用8位。同理,若是咱們的id字段佔了64位,那就能夠節省64倍的空間。並且,能夠利用位運算的特性,來快速實現統計、並集、交集等操做。

看過文章A的人有:1, 2, 4, 7:

1, 1, 0, 1, 0, 0, 1, 0

看過文章B的人有:1, 3, 4, 8:

1, 0, 1, 1, 0, 0, 0, 1

看過文章A且看過文章B的人有:

1, 1, 0, 1, 0, 0, 1, 0

&

1, 0, 1, 1, 0, 0, 0, 1

=

1, 0, 0, 1, 0, 0, 0, 0

獲得看過文章A且看過文章B的人有:1, 4

上面的例子只能放8位,若是個人id是9怎麼辦?

BitMap是一個一個上面這樣的數據來組成的。你可使用一個能夠擴容的整數數組來作,好比long數組。因此能夠無限擴展。

若是id比較稀疏怎麼辦?

好比我要存入的id多是1,101,1001這種比較稀疏的,若是用BitMap就會浪費一些空間。雖然如今開源的一些實現能夠經過記錄偏移量來解決這個問題,但也會由於頻繁的分裂影響性能。這種場景下,其實不建議使用BitMap

有興趣的同窗能夠了解一下谷歌開源的EWAHCompressedBitMap,它解決了輸入稀疏的問題。

BitMap實現

由於筆者主要熟悉Java語言,因此介紹一下Java語言對BitMap的實現。

JDK提供了一個BitMap的實現,叫BitSet,位於java.util包下。其底層使用的是一個long類型的數組,一個long表明一個word。但BitSet沒有解決上面提到的輸入稀疏的問題。谷歌開源的EWAHCompressedBitMap解決了輸入稀疏的問題。

Redis提供了bitmaps對象。實際上是使用的string對象,底層使用了咱們上篇文章提到的SDS。因此會有512M的最大限制,即最多能存2^32個數據。若是你的id是long類型的,佔64位,那可使用兩個bitmaps來存

由SDS的底層實現可知,它是能夠擴容和縮容的,可是若是輸入比較稀疏,仍然會浪費大量的內存。因此若是輸入很稀疏,也不建議使用Redis的bitmaps。

Redis bitmaps基本操做

carbon 6.png

總結

Redis提供了bitmaps對象。它在某些場景下能夠節省空間,並顯著提高性能。但若是輸入比較稀疏(好比網站註冊用戶有1億,但天天只有10萬用戶登陸),那還不如使用set。

另一方面,輸入只能是整形。若是是字符串類型的,就無法使用這個數據結構了。

關注公衆號:xy的技術圈

相關文章
相關標籤/搜索