lucene VInt(變長整數(shù) )

VInt 介紹

VInt (variable-length Integer) 變長整數(shù),指的是使用動態(tài)變化的字節(jié)數(shù)來表示整數(shù)脾还。我們熟悉的編程語言中肴楷,int 型都是由固定的 4 字節(jié)表示,好處是序列化和反序列化簡單荠呐;缺點是赛蔫,如果需要存儲大量的整數(shù)砂客,特別是數(shù)值較小的整數(shù)占比較大時,比較浪費存儲空間呵恢。因此在很多存儲系統(tǒng)中鞠值,往往使用變長整數(shù)來存儲整型數(shù)據(jù)從從而達到數(shù)據(jù)壓縮的效果。

原理

傳統(tǒng)的整型數(shù)值一般使用 4 字節(jié)來表示渗钉,而變長整數(shù)使用 1 到 5 字節(jié)來表示整型數(shù)值彤恶,每個字節(jié)的最高位為標志位,代表是否還存在下個字節(jié)鳄橘,低 7 位用來表示具體的數(shù)值內(nèi)容声离,如下所示:


byte 組織結(jié)構(gòu)

VInt 編碼過程:

  1. 首先從二進制低位開始選取 7 位,并判斷除低 7 位外瘫怜,其他位是否全 0术徊,如果是,執(zhí)行步驟 2鲸湃,否則執(zhí)行步驟 3赠涮;
  2. 將低 7 位寫入一個字節(jié),高位補 0 代表該數(shù)值所表示的最后一個字節(jié)暗挑,編碼完成笋除;
  3. 將低 7 位寫入一個字節(jié),高位補 1 代表下一個字節(jié)依然需要存儲該數(shù)值的部分數(shù)據(jù)炸裆,并將二進制無符號右移 (>>>) 7 位垃它,進入步驟 1

舉個例子,對于整數(shù) 129烹看,4 字節(jié)二進制表示為 00000000 00000000 00000000 10000001嗤瞎,VInt 第一個字節(jié)寫入的內(nèi)容為 1000 0001(高位為 1 表示下一個字節(jié)還有數(shù)據(jù)),第二個字節(jié)為 0000 0001 (高位為 0 表示這是最后一個字節(jié))听系。

VInt 解碼過程:

  1. 從第一個字節(jié)開始讀取,如果最高位為 0虹菲,代表最后一個字節(jié)靠胜,直接返回,否則毕源,將最高位置 0浪漠,進入步驟 2;
  2. 讀取下一個字節(jié)霎褐,如果高位為 0址愿,代表最后一個字節(jié),將該字節(jié)左移 7 位并或上上一次的結(jié)果冻璃,否則高位置 0响谓,重復(fù)步驟 2

129 解碼為:0(高位置 0)000 0001 | (0000 0001 << 7)= 0000 0000 1000 0001

lucene 實現(xiàn)

編碼(類 DataOutput)

  public final void writeVInt(int i) throws IOException {
    while ((i & ~0x7F) != 0) {
      writeByte((byte)((i & 0x7F) | 0x80));
      i >>>= 7;
    }
    writeByte((byte)i);
  }

解碼(類 DataInput)

 public int readVInt() throws IOException {
    /* This is the original code of this method,
     * but a Hotspot bug (see LUCENE-2975) corrupts the for-loop if
     * readByte() is inlined. So the loop was unwinded!
    byte b = readByte();
    int i = b & 0x7F;
    for (int shift = 7; (b & 0x80) != 0; shift += 7) {
      b = readByte();
      i |= (b & 0x7F) << shift;
    }
    return i;
    */
    byte b = readByte();
    if (b >= 0) return b;
    int i = b & 0x7F;
    b = readByte();
    i |= (b & 0x7F) << 7;
    if (b >= 0) return i;
    b = readByte();
    i |= (b & 0x7F) << 14;
    if (b >= 0) return i;
    b = readByte();
    i |= (b & 0x7F) << 21;
    if (b >= 0) return i;
    b = readByte();
    // Warning: the next ands use 0x0F / 0xF0 - beware copy/paste errors:
    i |= (b & 0x0F) << 28;
    if ((b & 0xF0) == 0) return i;
    throw new IOException("Invalid vInt detected (too many bits)");
  }

lucene 的代碼實現(xiàn)的非常優(yōu)雅损合,對照著上面的編解碼過程來看,清晰易懂娘纷。要注意的是嫁审,readVInt 中,最多執(zhí)行 5 次 readByte赖晶,原因是最多 5 個字節(jié)便能表示最大整型數(shù)值律适。每個字節(jié)除去一個標志位,真正表示數(shù)據(jù)的位數(shù)為 7 * 5 = 35遏插,比 32 位還多捂贿,足夠表示最大 int 數(shù)值。

總結(jié)

使用變長編碼后胳嘲,對于不同范圍的整數(shù)可以使用不同數(shù)量的 byte 來表示厂僧,特別在小數(shù)比較多的情況下,壓縮效率非常明顯胎围。因此吁系,在一些存儲系統(tǒng)(比如 lucene)中,常常使用變長編碼來節(jié)約存儲空間白魂。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末汽纤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子福荸,更是在濱河造成了極大的恐慌蕴坪,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敬锐,死亡現(xiàn)場離奇詭異背传,居然都是意外死亡,警方通過查閱死者的電腦和手機台夺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門径玖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人颤介,你說我怎么就攤上這事梳星。” “怎么了滚朵?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵冤灾,是天一觀的道長。 經(jīng)常有香客問我辕近,道長韵吨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任移宅,我火速辦了婚禮归粉,結(jié)果婚禮上椿疗,老公的妹妹穿的比我還像新娘。我一直安慰自己盏浇,他們只是感情好变丧,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绢掰,像睡著了一般痒蓬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上滴劲,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天攻晒,我揣著相機與錄音,去河邊找鬼班挖。 笑死鲁捏,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的萧芙。 我是一名探鬼主播给梅,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼双揪!你這毒婦竟也來了动羽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤渔期,失蹤者是張志新(化名)和其女友劉穎运吓,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疯趟,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡拘哨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了信峻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倦青。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖盹舞,靈堂內(nèi)的尸體忽然破棺而出产镐,到底是詐尸還是另有隱情,我是刑警寧澤矾策,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站峭沦,受9級特大地震影響贾虽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吼鱼,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一蓬豁、第九天 我趴在偏房一處隱蔽的房頂上張望绰咽。 院中可真熱鬧,春花似錦地粪、人聲如沸取募。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玩敏。三九已至,卻和暖如春质礼,著一層夾襖步出監(jiān)牢的瞬間旺聚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工眶蕉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留砰粹,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓造挽,卻偏偏與公主長得像碱璃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子饭入,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354