談談BitSet的缺點

主要談談BitSet的不足,而後重點說明開源Lucene的SparseFixedBitSet是如何解決的。數組

BitSet的優勢在於節省存儲空間,好比有10000個正整數範圍從0-9999,底層使用byte數組方式存儲大約佔用1250個字節,若是使用整形數組存儲大約佔用4*10000=40000個字節,如此節省了大約32倍的空間。優化

若是有100個正整數,但數值範圍在0-100000000之間,其中最大值爲99999999,這個時候用BitSet存儲將佔用12500000個字節,而用整形數組存儲大約佔用100*4=400個字節,所以BitSet存儲稀疏數據的時候反而是浪費空間的,解決的方法是使用稀疏BitSet,以Lucene的SparseFixedBitSet爲例:索引

(1)首先將存儲空間按照4096進行劃分,即數值範圍0-4095的爲一組、4096-8191的爲一組等等。it

         SparseFixedBitSet中開闢了二維數組long[][]進行存儲,數組的第一個下標表示組ID,好比1000的組ID=1000/4096=0。方法

(2)數組的第二個下標表示數值所在的數據塊ID,好比在原始的bitset中(底層用long數組)1000的數據塊ID=1000/64=15。這裏的意思是同樣的,但表示的方法不一樣,也是最最關鍵的地方!很明顯1000在數組的第二個下標中的位置必定不是15,否則費了這麼大勁等於沒優化,SparseFixedBitSet另外開劈了一個索引是用一維數組long[]表示的,數組下標是數值的組ID與二維數組的第一個下標同樣的意思,long值記錄的是1000的數據塊ID=15(注意是按位進行存儲的indexValue |=1<<15,因爲1個long值能夠表示64個數據塊,每一個數據塊的long能夠存儲64個數值正好64*64=4096,這就是爲何存儲空間按照4096劃分的緣由。)因爲只有1個數據塊,因此數據塊ID被變換成0,若是來了一個新數值800,它的數據塊ID=800/64=12即indexValue |=1<<12,此時有兩個數據塊了,原來數據塊ID=15的被變換成1,數據塊ID=12的被變換成0,再來一個新數據600的時候indexValue |=1<<9,原來數據塊ID=15的被變換成2,數據塊ID=12的被變換成1,數據塊ID=9的被變換成0。總結

(3)將上面的話用代碼總結一下:數據

    long[] index;二維數組

    long[][] bits;底層

    1000->index[0] |= 1<<15 ; bits[0][0] |=1<<1000;index

    800 -> index[0] |=1<<12 ;  bits[0][0] |=1<<800; bits[0][1] |=1<<1000;

    600 -> index[0] |=1<<9 ;   bits[0][0] |=1<<600; bits[0][1] |=1<<800; bits[0][2] |=1<<1000;

    所以數據塊ID=index中當前位後面1的個數:1000時index=00000000_00000000_00000000_00000000_00000000_00000000_01000000_00000000,因此1000的數據塊ID=0;

800時index=00000000_00000000_00000000_00000000_00000000_00000000_01001000_00000000,因此1000的數據塊ID=1,800的數據塊ID=0;

600時index=00000000_00000000_00000000_00000000_00000000_00000000_01001001_00000000,因此1000的數據塊ID=2,800的數據塊ID=1;600的數據塊ID=0;

相關文章
相關標籤/搜索