루씬 인 액션을 보던 중 텀벡터에 대한 얘기가 나와서 살펴보았다.
간단하게 색인을 해 놓고..
소스를 간단하게 만들어서 돌려보았다..
package kr.co.gshs.lucene.test;
import java.io.IOException;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.TermFreqVector;
import org.apache.lucene.index.TermPositionVector;
import org.apache.lucene.index.TermVectorOffsetInfo;
public class TermVectorTest {
public static void main(String[] args) throws IOException {
IndexReader reader = IndexReader.open("D:/lucene_data/test_index");
int maxDoc = reader.maxDoc();
System.out.println("maxDoc = " + maxDoc);
for(int i = 0; i < maxDoc && i < 10; i++) {
//System.out.println("i");
Document doc = reader.document(i);
String subject = doc.get("TITLE");
System.out.println("title = " + subject);
TermFreqVector termFreqVector = reader.getTermFreqVector(i, "TITLE");
TermPositionVector termPosition = (TermPositionVector)reader.getTermFreqVector(i, "TITLE");
String[] terms = termFreqVector.getTerms();
int[] freqs = termFreqVector.getTermFrequencies();
String[] termsPo = termPosition.getTerms();
int[] termPo = termPosition.getTermFrequencies();
//System.out.println("termPo = ["+termPo.length+"]");
for(int j = 0; j < terms.length; j++) {
System.out.println("TERM = " + terms[j] + "["+freqs[j]+"]");
}
for(int k = 0; k < termPo.length; k++) {
System.out.println("TERMs = " + termsPo[k] + "["+termPo[k]+"]");
TermVectorOffsetInfo[] offsets = termPosition.getOffsets(k);
int[] tp = termPosition.getTermPositions(k);
for(int kk = 0; kk < tp.length; kk++) {
System.out.println("term position : " + tp[kk]);
}
for(int cp = 0; cp <offsets.length; cp++) {
System.out.println("start_off_set : " + offsets[cp].getStartOffset());
System.out.println("end_off_set : " + offsets[cp].getEndOffset());
}
}
}
}
}
일단 검정 부분만 보면...
IndexReader로 부터 getTermFreqVector 메서드를 통해 TermFreqVector 를 생성하여
getTerms()와 getTermFrequencies()를 사용하여 TITLE 필드에 있는 컨텐츠의
텀과 빈도수를 가져오고 있다.
실제로 색인되어 있는대로 가져오기 때문에 제목이 만약에
"테스트 테스트 테스트"라면 이 넘은
terms[0] = 테스트
freqs[0] = 3
이 된다. 만약 동의어에 의해서 "테스트 입니다" 라는 제목이
"테스트 test 입니다" 라고 색인이 되어 있다고 한다면 (물론 offset이나 position은
테스트와 test가 동일하게 색인)
terms = {테스트, test, 입니다}
freqs = {1, 1, 1} 이 된다.
참고로 이 메서드를 사용하기 위해서는 색인시
Field field = new Field(...., Field.TermVector.YES) 를 주어야 한다.
이제 파랑 부분을 보자.
TermPositionVector termPosition = (TermPositionVector)reader.getTermFreqVector(i, "TITLE");
다운 캐스팅을 통해서 TermPositionVector 를 가져오고 있다.
이 부분을 실행시 만약 색인 할 때
Field.TermVector.WITH_POSITIONS_OFFSETS 이나 WITH_POSITION 조건을 주지 않으면 , ClassCastException이 발생한다.
위 조건을 주어 색인을 하고 TermPositionVector를 가지고 와서
위 for문을 돌리면 아래와 같은 결과가 나온다.
title = Siebel주문Interface항목
TERMs = interface[1]
term position : 2
start_off_set : 8
end_off_set : 17
TERMs = siebel[1]
term position : 0
start_off_set : 0
end_off_set : 6
TERMs = 주문[1]
term position : 1
start_off_set : 6
end_off_set : 8
TERMs = 항목[1]
term position : 3
start_off_set : 17
end_off_set : 19
TermFreqVector 처럼 term와 Freq도 가져올 수 있고
색인되어 있는 정보를 사용하여 텀의 position과 offset을 가져올 수도 있다.
다만..이 정보를 포함해서 색인할때의 속도라던가...그런 것들은 비교를 하지 못 했고..
이걸 어디에 쓰는게 가장 효과적일까...하는 생각이 들기도 한다.;;
여기저기 찾아보니 TermPositionVector는 Highlight 클래스에서 사용하는 것 같다.
색인에 정보가 있으면 TermPositionVector를 가져와서 하이라이트 할 부분을 찾아내고
없으면 Analyzer를 통해 다시 tokenStream을 뽑아내서 찾아내는 방식이 아닐까...
하는 생각이 든다.
그거 말고 어디 또 좋은데 쓸 수 있을것 같은데...;;;