Lucene에서 variable int 표현하는법

오늘 Lucene에서 쓰이는 인덱스 시스템을 분석하면서 Vint 타입을 어떻게 처리하는지 코드를 분석해봤다.

int면 int지 왜 Vint인지, 예전에 DB를 공부하면서 vchar타입인가? 하는 V자가 붙은 타입을 봤는데, 이 것들의 설명이 그 대상체의 크기에 맞게 disk에 공간을 차지한다는 개념이였다.

물론 Lucene도 마찬가지로 이 부분에 대해서 고려한 부분이 있었다. 이 코드를 이해하고 ‘아~!’ 하고 머리를 쳤으니 참 기쁘기 한량없었다.

쓸데없이 군더더기 빼고 Python으로 구현된 코드를 첨부했다. (실제 Python이 Sudo 코드로 많이 쓰이는 추세란다.)
자바로 구현된 부분을 확인해봤지만 역시 구현 방법은 똑같았다.

….
def writeVInt(i):
 while (i & ~0x7F) != 0:
    writeByte((i & 0x7F) | 0x80)
    i = i >> 7
 writeByte(i)
….

(클래스 개념에 대해서 살짝 감추려고 코드를 약간 손봤다.)

아래의 코드 샘플을 보자면, 양의 int 형만을 나타내고 각 바이트의 마지막 비트는 다음 바이트가 있는지 나타내는 역할을 한다. 위 코드에서 첫번째 while문으로 주어진 조건부분이 128이상의 숫자인지를 판별하는 부분이다.

그리고 “writeByte((i & 0x7F) | 0x80)” 이 부분의 코드는 다음 하위 1byte만을 쓰기복원하기 위한 코드인다. 제일 상위 비트에는 1 비트가 존재하는걸 확인 했으므로 or 연산을 준것이다.

그리고 우로 shift연산을 해주는데 이 부분은 8비트중에서 8번째 비트를 더 많은 바이트가 있는지를 확인하는 부분으로 쓰기 때문에 7비트 만큼 쉬프트 연산을 해준것이다. (사실, 처음에 8비트가 아닌가 했는데, 8의 배수째의 비트가 항상 겹치는걸로 이해하면 될것이다.)

아래는 보기 쉽게 정리한 표이다.
Lucene 사이트에서 살짝 빌려왔다.

VInt Encoding Example

Value

First byte

Second byte

Third byte

0

00000000

1

00000001

2

00000010

127

01111111

128

10000000

00000001

129

10000001

00000001

130

10000010

00000001

16,383

11111111

01111111

16,384

10000000

10000000

00000001

16,385

10000001

10000000

00000001

위 코드와 설명이 처음에 이해하기 힘들것이다. 그렇다면 여러 숫자를 가지고 위 표와 같이 표현이 어떤식으로 되는지에 직접 연습장에 적어가면서 해보면 이해가 될거라는 생각이 든다.

이런식으로 해서 int를 가변적으로 메모리나 Disk에 저장할수 있다.(Lucene에서는 5바이트로 한정해 놓았다)
int 형을 많이 쓰는 검색엔진 파일 시스템으로 보자면 상당히 용량상 잇점을 볼수 있는 구조적 기반이 될거라는 생각을 해본다.

참으로 많은 이야기를 하는 코드 몇줄이였던거 같다. 그동안 비트연산에 대해서 약간 소홀히 해서 처음엔 보기 힘들었지만, 이해하고 나니 참 아름답게 느껴지기까지 하는군.
역시나 남이 짠 코드를 보는게 쉬운게 아니지만, 한 프로그램을 분석하다 보면 배울점이 상당히 많다는걸 줄곳 느낀다.

고수들의 간결하고 많은 이야기를 하는 코드를 보면서 저절로 흉내를 내려고 하니 시간투자를 좀 해봐야 겠다는 생각이 다시한번 들기도 하고.

그나저나 내일은 어떤 코드조각을 탐구해볼까 …. ㅋㅋㅋ

CC BY-NC 4.0 Lucene에서 variable int 표현하는법 by from __future__ import dream is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.