ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Fastcat] FullIndex를 알아보자. (2)
    개발하면서/코드보면서 2011. 8. 13. 00:03
    반응형

    SegmentWriter에 대해 알아보는 시간이다.
    SegmentWriter에는  문서 텍스트 및 포스팅 정보, 렉시콘, 필터, 정렬, 그룹에 필요한 정보를 가공하는 역할을 한다.

     SourceReader에서 하나의 문서를 schema.xml에서 정의한 속성대로 저장한다.

    한문서를 읽을 때마다   DocumentWriter, SearchWriter, FilterWriter, SortWriter, GroupWriter의 write를 실행한다.

    while(!requestStop && sourceReader.hasNext()){
    	Document doc = sourceReader.next();
        int docNo = documentWriter.write(doc);
    	if(lastDocNo != docNo)
    		throw new IRException("~~~");
    
    	searchWriter.write(doc);
    	filterWriter.write(doc);
    	sortWriter.write(doc);
    	groupWriter.write(doc);
    	lastDocNo++;
    				
    	if(lastDocNo % 10000 == 0){
    		lapTime = System.currentTimeMillis();
    	}
    }

     

    먼저 DocumentWriter를 알아보자

     

    압축된 문서를 저장하는 docOutput, docOutput에서 문서 위치를 저장하는 positionOutput, 삭제할 문서 목록을 저장하는 deleteSet,

    마지막으로 PrimaryKey를 저장하는 pkIndexWriter DocumentWriter를 실행하면 총 4개의 파일이 생성된다.

    우선 문서 저장(docOutput, positionOutput)에 대해 알아보자.

    for (int i = 0; i < document.size(); i++) {
    	Field f = document.get(i);
    ..............
    	if (fields.get(i).store) {
    		IOUtil.writeVariableByte(fbaos, buffer.pos());
    		fbaos.writeBytes(buffer.array(), 0,  buffer.pos());
    	} else {
    		IOUtil.writeVariableByte(fbaos, 0);
    	}
    }

     

    하나의 문서에 대해서 Schema에서 지정한 필드 수만큼 for문을 돈다.

    Field를 하나씩 돌면서 이 데이타를 저장할지 말지를 { if(fields.get(i).store)} 결정하고 byte 배열 fbaos 에 저장한다.

    if((localDocNo + 1) % DOCUMENT_BLOCK_SIZE == 0){
    	writeInternal();
    }​


    내부문서 번호+1이 DOCUMENT_BLOCK_SIZE의 배수일 경우 writeInternal을 실행하는데 writeInternal을 보면 알겠지만 fbaos을
    압축해서 파일에 기록하는 기능을 한다.

     

     


    위 그림이 압축된 문서와 압축된 문서의 위치 정보를 저장할때의 구조이다.
    ( 안쓴 부분이 있는데, 압축된 문서의 위치 저장할때, 맨 앞부분, header에는 총 문서번호와 DOCUMENT_BLOCK_SIZE를 기록합니다.)
    검색할때는 문서번호 / DOCUMENT_BLOCK_SIZE 의 몫이 압축된 문서의 위치정보이고 압축된 문서를 가져오면,
    압축을 풀고  문서번호 / DOCUMENT_BLOCK_SIZE 의 나머지로 문서를 가져올것같다.
    (아직 검색부분은 보지못했는데, 그냥 저의 생각입니다.;;)
    다음은 PrimaryKeyIndexWriter를 보자. field의 primary가 true인 필드 데이타를 저장할것이다.
    int preDocNo = pkIndexWriter.put(buffer.array(), buffer.pos(), localDocNo);
    Primary Index는 아래와 같은 구조를 가진다.    (ID가 14401인 데이타 저장)

     

     

     

    bucket과 keyPos는 int형 배열이고, array는 byte형 배열이다.

    bucket의 배열 인덱스는 필드데이터를 해싱한 결과이고, 값은 keyPos 배열의 인덱스가 저장되어있다.

    keyPos의  배열 인덱스는 sequence 저장이 되고, 값은 데이터가 저장된 array의 시작 인덱스가 저장되어있다.

    intValueArray의 배열 인덱스는 keyPos의 인덱스와 동일하다. 배열의 값은 내부 문서번호가 저장되어있다.

    keyPos의 4번째 데이타와 intValueArray의 4번째 내부문서번호는 서로 연결된(?) 데이터이다.

     

    int형 배열 nextIdx도 있는데, 해싱의 중복이 발생하기 때문에 이를 해결하기 위해 만든 변수이다.

    해싱한 결과들이 중복이 없다면, bucket과 keyPos는 1:1관계가 되어서 바로바로 찾으면 된다.


    하지만 중복이 발생한다면 1:N관계가 된다. bucket은 하나의 keyPos만 가리킬수가 있어서 데이타가 다를경우
    nextIdx에 다음 이동할 keyPos의 인덱스값을 저장해서 탐색을 진행한다.
    동일한 데이타가 입력이 되었다는건 수정이 일어났다고 볼수있으므로, 기존에 저장되어 있는 문서번호를 리턴해서
    다음에 알아볼 삭제 문서 체크에 사용한다.
     
    모든 문서에 대해서 primaryKeyIndex 처리를 하면 output, indexOutput을 생성하는데 output에는 [primary가 true인
    (data의 길이, data, 문서번호)] 형식으로 저장이 되고, indexOuptut에는 indexInterval마다 기록을 하는데
    [primary가 true인 (data의 길이, data, output의 position)] 형식으로 저장이 된다.


    검색할때,  indexOutput에 있는 data를 비교하면서 indexOutput의 data보다 크거나 같은 부분을 찾고
    output을 뒤지는 방식으로 진행될것같다.  (이것도 추측...)



    마지막으로 알아볼건 삭제 문서파일 생성이다.
    int preDocNo = pkIndexWriter.put(buffer.array(),buffer.pos(), localDocNo);
    preDocNo은 삭제할 문서번호이다.

    대강의 전체 문서의 갯수를 구한후 하나의 long 변수는 64개의 문서를 체크한다.
    64번째 문서가 삭제되는거라고 하면
    0000 0000  0000 0000  0000 0000 0000 0000  0000 0000  0000 0000  0000 0000 0000 0001
    이 되는것이다.
    모든 문서에 대해 delete 검사를 마치면 save함수로 파일에 저장한다.

    반응형

    댓글

Designed by Tistory.