DotLucene: 뛰어난 full-text 검색 엔진
37 라인으로 Full-Text 검색 코드를 작성할 수 있을까? 글쎄, 나는 약간의 편법을 쓸 예정이고, 이를 위해 DotLucene를 이용할 것이다. DotLucene은 Jakarta Lucene 검색 엔진을 George Aroush et al이 .NET으로 포팅 한 것이다. 기능은 대략 이러하다.
- Win Form이나 console application 등 ASP.NET에서 사용 가능하다.
- 매우 좋은 성능을 낸다.
- 검색 결과에 순위가 매겨져 있다.
- 결과에 검색 쿼리가 강조 된다.
- 구조적이거나 비구조적인 데이터를 검색한다.
- 메타베이스 검색
- 색인의 크기는 색인된 텍스트의 대략 30%이다.
- 또한 완전하게 색인된 문서들을 저장할 수 있다.
- 244 KB 짜리 단일 어셈블리에서 Pure managed .NET
- 매우 친숙한 라이센스(Apache Software License 2.0).
- 지역화가 가능하다(브라질어, 체코어, 중국어, 네덜란드어, 영어, 프랑스어, 일본어, 한국어 그리고 러시아어를 포함).
- 확장 가능하다(소스코드가 포함되어 있다).
경고
라인 수를 너무 심각하게 따지지 말라. 여기에서는 핵심 기능을 37 라인의 코드를 넘기지 않고 구현하는 것을 보여줄 것이다. 하지만, 실제 애플리케이션에서는 더 많은 시간을 들여야 할 수도 있다.
데모 프로젝트
어떻게 동작하는 지 보여줄 간단한 데모 프로젝트를 빌드 할 것이다.
- 색인 HTML 파일들은 특정 디텍토리 안에서 찾는다(하위 디렉토리 포함).
- ASP.NET 애플리케이션을 통한 색인 검색
- 검색 결과의 쿼리 단어를 강조
DotLucene은 더 많은 잠재적인 가능성을 가지고 있다. 실제 애플리케이션에서는 이러한 기능들을 원할 것이다.
- 디렉토리에 새로운 문서가 나타나면 이를 색인에 추가한다. 따라서 전체 색인을 재빌드 할 필요가 없다.
- 다른 파일 타입을 포함한다. DotLucene은 평문(plain text)으로 변환할 수 있는 어떠한 파일 타입이라도 색인 할 수 있다.
왜 Microsoft Indexing Server를 이용하지 않는가?
만약 Indexing Server에 만족한다면, 별 문제없다. 하지만, DotLucene은 더 많은 강점들을 가지고 있다.
- DotLucene은 100% managed code의 단일 어셈블리이다. 이는 외부에 의존할 필요가 없음을 말한다.
- shared hosting를 이용하기 때문에, 미리 색인을 준비하였다면 퍼미션을 줄 필요가 없다.
- 데이터베이스나 웹 등의 소스에서라도 어떠한 타입의 데이터라도 색인하여 사용할 수 있다. 때문에 평문을 indexer로 제공해야 할 필요가 있다. 소스의 로딩과 파싱은 당신의 선택에 달려 있다.
- 색인에 포함된 특정한 속성("fields")을 줄 수 있다. 이들 필드를 통해 검색할 수 있다.
- 오픈 소스이다.
- 쉽게 확장 가능하다.
1 라인: 색인 생성
다음의 코드는 새로운 색인을 생성하여 디스크에 저장한다. directory는 색인이 저장될 디렉토리 경로이다.
IndexWriter writer =
new IndexWriter(directory, new StandardAnalyzer(), true);
이번 예제에서는, scratch로부터 색인을 생성한다. 이는 필수가 아니며, 존재하는 색인을 열거나 문서를 추가할 수 있다. 게다가 존재하는 문서를 삭제하거나 새로운 버전을 추가하여 업데이트 할 수 있다.
2 – 12 라인: 문서 추가
각 HTML 문서에서 색인에 두 필드를 추가한다.
- text 필드는 HTML 파일 (with stripped tags)의 텍스트를 포함한다. 텍스트는 스스로 색인에 저장되지 않는다.
- path 필드는 파일 경로를 포함한다. 여기에 지정된 색인에 전체가 색인되고 저장된다.
public void AddHtmlDocument(string path)
{
Document doc = new Document();
string rawText;
using (StreamReader sr =
new StreamReader(path, System.Text.Encoding.Default))
{
rawText = parseHtml(sr.ReadToEnd());
}
doc.Add(Field.UnStored("text", rawText));
doc.Add(Field.Keyword("path", path));
writer.AddDocument(doc);
}
13 – 14 라인: 색인의 최적화와 저장
문서를 추가한 후에 indexer를 닫아야 한다. 최적화는 검색 성능을 향상시킨다.
writer.Optimize();
writer.Close();
15 라인: 검색을 위한 색인 열기
어떠한 검색이라도 실행하기 전에 색인을 열어야 한다. directory 는 색인이 저장된 디렉토리 경로이다.
IndexSearcher searcher = new IndexSearcher(directory);
16 – 27 라인: 검색
이제 쿼리를 파싱 할 수 있다 (text는 검색을 위한 기본 필드이다).
Query query =
QueryParser.Parse(q, "text", new StandardAnalyzer());
Hits hits = searcher.Search(query);
변수 hits는 결과 문서들의 집합이다. 검색은 이를 통해 이루어 지고, 결과는 DataTable에 저장된다.
DataTable dt = new DataTable();
dt.Columns.Add("path", typeof(string));
dt.Columns.Add("sample", typeof(string));
for (int i = 0; i < hits.Length(); i++)
{
// get the document from index
Document doc = hits.Doc(i);
// get the document filename
// we can''t get the text from the index
//because we didn''t store it there
DataRow row = dt.NewRow();
row["path"] = doc.Get("path");
dt.Rows.Add(row);
}
Lines 28 - 37: 쿼리 강조
highlighter를 생성하자. 강조에는 굵게(<B>phrase</B>)를 사용한다..
QueryHighlightExtractor highlighter =
new QueryHighlightExtractor(query, new StandardAnalyzer(),
"<B>", "</B>");
결과를 fetch하는 동안, 오리지널 텍스트의 적절한 부분을 로드한다.
for (int i = 0; i < hits.Length(); i++)
{
// ...
string plainText;
using (StreamReader sr =
new StreamReader(doc.Get("filename"),
System.Text.Encoding.Default))
{
plainText = parseHtml(sr.ReadToEnd());
}
row["sample"] =
highlighter.GetBestFragments(plainText, 80, 2, "...");
// ...
}
리소스들
'.net' 카테고리의 다른 글
Repeater Control (II) (0) | 2007.05.03 |
---|---|
Repeater Control (1) (0) | 2007.05.03 |
커스텀 로그인 컨트롤 (1) | 2007.05.03 |
다중 데이터테이블을 한개의 그리드뷰에 바인딩하기 (0) | 2007.05.03 |
WebPart 프레임워크의 이해 - 커스터마이징 가능한 페이지 만들기6 (1) | 2007.05.03 |