검색엔진

Hagi 2009. 11. 10. 01:56

색인은 다음의 과정을 거친다.

  1. 문서를 분석해서 tokenizing 한다. 
  2. field를 포함한 lucene document를 생성한다. 
  3. lucene document를 색인한다.

Lucene는 색인파일을 만들기 위해서 IndexWriter를 제공한다. 

(참고 : http://www.joinc.co.kr/modules/moniwiki/wiki.php/JCvs/Search/Document/Lucene/Indexer)

==============================================================================================================================

 검색엔진에서 Robot을 만들다가 많은 고민을 했다. DB는 오라클같은 관계형DBMS를 쓰면 느리다던데... 

 Lucene을 먼저 공부했다면 이런 고민은 오래하지 않았을 텐데라는 아쉬움이 남는다. 

 Lucene으로 제작된 Nutch는 Hadoop을 기반으로 한 HDFS를 쓴다고 한다. 

 아무튼 이것의 기반은 index이다. 아니 모든 검색엔진의 DATA는 index이다. 


 Lucene In Action이라는 책을 공부하다가 Lucene 1.X 버전과 2.X버전이 많이 틀린것 같아서 예제를 수정해보았다.

 제 1장 루씬과의 첫만남 - 예제 1.1 (p12)

 package start.hagi.ironwill.lucene.index;


import java.io.File;

import java.io.FileReader;

import java.io.IOException;


import org.apache.lucene.analysis.kr.KoreanAnalyzer;

import org.apache.lucene.document.Document;

import org.apache.lucene.document.Field;

import org.apache.lucene.index.IndexWriter;

import org.apache.lucene.index.IndexWriter.MaxFieldLength;

import org.apache.lucene.store.Directory;

import org.apache.lucene.store.FSDirectory;


public class Indexer {

private File indexPath;

private File dataPath;

public Indexer(){

indexPath = new File("C:/project/storage/lucene/index");//index 폴더는 만들지 않더라도 자동생성되게 함 

if(!indexPath.exists()){

indexPath.mkdir();

}

dataPath = new File("C:/project/storage/lucene/data"); //이곳에 .txt 파일을 집어 넣어야함

this.setDataPath(dataPath); this.setIndexPath(indexPath);

}

public static void main(String[] args) throws IOException{

Indexer idr = new Indexer();

int numIndexed = idr.index(idr.getDataPath(),idr.getIndexPath());

System.out.println("총 "+numIndexed+"개의 파일을 인덱스함");

}

public int index(File dirPath, File indexPath) throws IOException {

Directory indexDir = FSDirectory.open(indexPath); //디스크의 파일 시스템에 색인을 저장

IndexWriter writer = new IndexWriter(indexDir,new KoreanAnalyzer(),MaxFieldLength.UNLIMITED);

writer.setUseCompoundFile(false);

indexDirectory(writer,dataPath);

int numIndexed = writer.maxDoc();

writer.optimize();

writer.close();

return numIndexed;

}

public void indexDirectory(IndexWriter writer, File dataPath) throws IOException {

File[] files = dataPath.listFiles();

for(int i=0;i<files.length;i++){

File f = files[i];

if(f.isDirectory()){

indexDirectory(writer, f); //디렉토리일 경우 다시한번 파일을 읽어들임(재귀호출)

}else if(f.getName().endsWith(".txt")){

indexFile(i,writer,f);    //텍스트 파일일 경우 인덱스함 

}

}

}

public void indexFile(int i,IndexWriter writer, File file) throws IOException {

if(file.isHidden()||!file.exists()||!file.canRead()){

return;

}

System.out.println("["+i+"]파일 "+file.getCanonicalPath()+"를 인덱스 중입니다");

Document doc = new Document();

//Document에 필드 추가

doc.add(new Field("contents", new FileReader(file)));//잘라져서 색인되지만, 저장되지는 않는다.

doc.add(new Field(

"filename", 

file.getCanonicalPath(), //filename이라는 키값은 file의 상대경로한다.

Field.Store.YES ,        //이것을 저장한다. 

Field.Index.ANALYZED)    //Analyzer에 의해 잘라져서 색인된다.

);

writer.addDocument(doc);

}

public File getIndexPath() {

return indexPath;

}

public void setIndexPath(File indexPath) {

this.indexPath = indexPath;

}

public File getDataPath() {

return dataPath;

}

public void setDataPath(File dataPath) {

this.dataPath = dataPath;

}

}


여기서 사용한 Analyzer는 현재 루씬한글분석기 오픈소스 프로젝트 에서 배포한 것을 사용하였다. 

- 첨부파일

koreananalyzer_090629.jar