Computer Science/JAVA Lucene

Hello Lucene#2(HelloLucene 메소드)

sgwon 2022. 3. 20. 19:26

저번 글에서는 HelloLucene클래스파일의 메인함수에 대해서 알아보았다. 이번에는 메인함수에서 사용한 HelloLucene의 내부 메소드를 알아보자.

IDE : Eclipse IDE 2022-3

JDK : 1.7.2

Maven : 1.7

Junit : 4.11

Lucene : 7.1.0


1. addDoc

private void addDoc(IndexWriter w, String title, String isbn) throws IOException {
    // TODO Auto-generated method stub
    Document doc = new Document();

    doc.add(new TextField("title", title, Field.Store.YES));
    doc.add(new StringField("isbn", isbn, Field.Store.YES));

    w.addDocument(doc);
}

addDoc메소드는 메인함수에서는 직접적으로 드러나진 않지만 createIndex메소드에서 사용된다. 여기서는 파라미터로 IndexWriter와 String 문자열 두개를 받는다. 여기서 IndexWriter란 어떤 파라미터일까?

 

IndexWriter

이 클래스는 Document를 받아 색인하는데 사용하는 클래스로 내부에 이 색인파일을 읽기위한 IndexReader클래스가 있다. 

Directory

IndexWriter가 색인하는데 필요한 클래스로 루씬에서 기본적으로 제공하는 디렉토리중에 하나가 RAMDirectory가 있다. 이것은 JVM에 공간을 만들어 색인파일을 작성하는 클래스로 addDoc을 사용하는 createIndex에 들어있다.(RAM디렉토리는 JVM가 내려가면 사라진다.)

Document

여러개의 Feild로 이루어진 객체, Document로 실행된 객체에 메소드에서 받은 인자를 각각 TextFeild와 StringFeild로 저장한다.

그러고 완성된 Document를 IndexWriter로 선언된 w에 색인하면서 해당 메소드는 종료된다.

여기서 doc에 add메소드를 사용할 때 세번째 옵션으로 'Field.Store.Yes'옵션이 있는데 이는 중요한 옵션으로 색인파일에서 해당 값을 가지고 있겠다는 뜻이다. 이것을 Yes로 지정해야 IndexSearcher에서 검색하여 해당필드의 값을 가져올 수 있다. 해당 코드에는 표기되지 않았으나 4번째칸에 다른 옵션을 추가 할 수 있다. 이는 나중에 기회가 된다면 다시 포스팅 해야겠다.


2. createIndex

@Override
public Directory createIndex(String[][] docs, Analyzer analyzer) throws IOException {
    // TODO Auto-generated method stub
    // 1. Index
    Directory index = new RAMDirectory();

    IndexWriterConfig config = new IndexWriterConfig(analyzer);
    IndexWriter w = new IndexWriter(index, config);

    for(String[] doc: docs) {
        addDoc(w, doc[0], doc[1]);
    }

    w.close();

    return index;
}

이 메소드는 분석기와 이중배열로 이루어진 텍스트를 받아 addDoc을 통해 색인된 Directory로 반환시키는 메소드이다.

위에서 설명한 대로 RAMDirectory를 사용하여 index를 생성하는데 해당 디렉토리는 JVM에 가상공간을 만들어 저장하기때문에 만약에 JVM가 내려가게 되면 함께 사라지게 된다. 하지만 속도가 빠르기 때문에 작은 용량의 파일을 색인할 때 용이하다.

 

IndexWriter

addDoc에서 인자로 받았던 IndexWriter가 여기서 생성된다. 생성하기전에 config에 인자로 받은 분석기(Analyzer)를 설정한다.

여기서 추가적으로 IndexWriterConfig 객체를 통해 더 많은 것을 설정 할 수 있으나 분석기설정은 필수로 해야하는 것으로 보인다.

분석기 설정을 추가할 때 주의할 점은 실제로 검색에 사용되는 분석기색인하는데 사용하는 분석기는 같은 것을 사용해야 한다는 것이다.

분석기마다 tokenization하는 방식에 차이가 있기때문에 통일 되어야 하는 것이다.

 

for문을 사용하여 색인되지않은 날 것의 파일을 하나 씩 인자로 받아 addDoc을 이용해 Index에 Write한다. 작업이 끝나게 되면 IndexWriter를 종료하고 완성된 index를 반환한다.


 

3. search

@Override
public String[][] search(Directory index, String Querystr, Analyzer analyzer) throws IOException, org.apache.lucene.queryparser.classic.ParseException, ParseException{
    // TODO Auto-generated method stub
    Query q = new QueryParser("title", analyzer).parse(Querystr);

    int hitsPerPage = 10;
    IndexReader reader = DirectoryReader.open(index);
    IndexSearcher searcher = new IndexSearcher(reader);

    TopScoreDocCollector collector = TopScoreDocCollector.create(hitsPerPage);
    searcher.search(q, collector);
    ScoreDoc[] hits = collector.topDocs().scoreDocs;

    String[][] result = new String[hits.length][2];
    for(int i=0; i<hits.length; i++) {
        int docId = hits[i].doc;
        Document d = searcher.doc(docId);
        result[i][0] = d.get("title");
        result[i][1] = d.get("isbn");
    }
reader.close();
return result;
}

이 클래스의 핵심이라고 할 수 있는 실질적으로 검색을 실행하는 메소드인 search메소드이다. 해당 메소드는 인자로 검색의 표적이 될 Directory, 검색할 쿼리인 String, 토큰화된 Directroy를 분석할 검색기인 Analyzer를 받는다.

Query

쿼리로 하기로 했지만 아직 문자열인 인자를 메소드 내에서 색인과 키워드정보가 포함된 Query로 생성한다.

IndexReader & IndexSearcher

인자로 받은 디렉토리를 DirectoryReader.open()을 사용하여 IndexReader를 선언하고 해당 reader를 인자로 하여 IndexSearcher를 생성한다. 여기서 IndexReader는 생성시점의 index에서 스냅샷을 가지기 때문에 생성이후 index가 수정되더라도 Reader는 수정전의 index파일을 유지한다. IndexSearcher는 reader를 통해 index의 색인에 접근하는 객체이다

TopScoreDocCollector 

해당 객체는 IndexSearcher를 이용하는데 필요한 객체로 쿼리에 따른 hit수에 따라 내림차순으로, 순위가 똑같다면 해당 문장이 가진Document ID를 기준으로 오름차순으로 하여 정렬된 TopDoc으로 반환하게 해준다. create()의 인자값으로 들어가는 int값은 간단히 말해 최대검색 개수로 볼 수 있다.

HitsPerPage = 1일 경우 2개가 나오던 결과가 1개가 나온다.

ScoreDoc

검색결과로 저장된 TopDoc의 ScoreDocs를 통해 최고조회수(?)를 불러와 저장한다.

그 후 검색결과의 양만큼 길이2의 문자배열이 들어간 이중문자배열을 생성한 후 hits에 저장된 결과 하나씩 Document ID값을 받아내 

searcher를 한 번더 사용하여 해당 ID의 Document를 불러내어 해당 "title"색인과 "isbn"색인의 값을 hits에 저장한다.

 

작업이 끝나면 reader를 종료한 후 hits를 반환한다.


이번엔 doc을 이중문자배열로 하여 시작했지만 다음 포스팅에는 하나의 텍스트파일을 불러와 똑같이 StandardAnalyzer를 이용하여 token화 하고 해당 메소드들을 다시 이용하여 검색해보는 내용을 올려보겠다.

'Computer Science > JAVA Lucene' 카테고리의 다른 글

Hello Lucene #1(HelloLucene main함수)  (0) 2022.03.20