본문 바로가기
Lucene/Lucene In Action

[루씬 인 액션] 1. 루씬(Lucene)의 개념 및 구조

by 잭피 2020. 11. 8.

루씬이란?

→ 루씬은 자바로 만들어진 고성능 정보 검색(IR : information retrieval) 라이브러리입니다

(IR : 문서를 검색하거나, 문서의 내용을 검색하거나, 문서와 연관된 메타 정보를 검색하는 과정을 뜻합니다)

 

루씬은 파일 검색이나 웹 문서 수집, 웹 검색 등에 바로 사용할 수 있는 애플리케이션이 아니고,

검색 기능을 갖고 있는 애플리케이션을 개발할 때 사용할 수 있는 라이브러리입니다

 

루씬은 색인과 검색기능에만 집중하고 강력하게 지원해줍니다

(색인 : 간단히 말해 특정 단어로 직접 이동할 수 있는 자료구조라고 보면 되고, 정보 검색에서 말하는 색인의 개념은 일반적인 책의 뒤에 있는 색인과 동일합니다)

 

루씬은 검색 대상 확보(수집)와 관련된 기능은 포함 하지 않습니다

 

루씬과 검색 애플리케이션 구조 

검색 대상 텍스트 확보

수집기를 사용해 색인할 대상 문서를 수집합니다

루씬은 수집에 관련한 기능은 포함하지 않습니다

루씬 문서 생성

위에서 검색할 대상 문서의 원본을 확보한 후, 원본을 루씬에서 사용하는 개별 단위

즉 문서로 변환해야 합니다 

 

루씬 문서는 여러 개의 필드로 구성됩니다

예를 들어, 책에 대한 정보를 검색한다면, 각 문서에 제목, 본문, 요약, 저자..등등이 들어가야합니다

이런 필드를 구성할 때, 원본에 없는 정보를 추가해 필드를 생성할 수도 있습니다

(텍스트 대상 의미 분석을 하여 별도의 필드에 보관)

 

또한, 색인 과정에 문서나 필드 단위로 중요도(boost) 값을 지정할 수 있습니다

거의 모든 검색 엔진은 자동으로 내용의 길이가 긴 필드에 비해 길이가 짧은 필드의 내용이 중요도가 높습니다

(책 한 권에 해당하는 내용 필드에 포함 단어보단 제목 필드에 더 많은 중요한 단어가 있음)

문서 텍스트 분석

이렇게 원본 문서에서 루씬 문서를 만들고 나면, 텍스트를 토큰이라 부르는 단위로 자릅니다

→ 토큰 추출 작업이 텍스트 분석 과정에서 가장 중요한 작업 중 하나입니다

(토큰이란 사람이 눈으로 보는 단어를 뜻합니다)

 

여기서 여러가지 상항을 결정해야 합니다

ex) "휴대폰"을 검색하면 "핸드폰"이라는 토큰도 검색?

두 개 이상의 단어가 연결된 경우 하나의 토큰으로 처리?

영문의 경우 대소문자 구분?

 

루씬에는 다수의 텍스트 분석기가 내장되어있습니다

필요한 경우 입맛에 맞는 별도의 분석기를 직접 구현하거나, 여러 개의 내장된 분석기를 연결해 원하는 분석리를 구성할 수 있습니다

이제 토큰까지 추출하고 나면 색인에 보관하는 일만 남았습니다

색인에 문서 추가

색인 과정이 끝나면 문서가 색인에 추가됩니다

루씬에는 이미 문서를 색인에 추가하는 데 필요한 모든 기능이 준비되어있습니다

 

검색 과정

검색은 색인에 들어있는 토큰을 기준으로 해당하는 토큰이 포함된 문서를 찾아내는 과정입니다

검색의 품질은 흔히 정확도와 재현율로 표현합니다

(정확도 : 관련없는 문서를 얼마나 정확하게 제거하는지)

(재현율 : 얼마나 빼먹지 않고 찾아주는지)

검색 사용자 인터페이스

인터페이스는 최대한 간결하게 유지하는 편이 좋습니다

조금이라도 고급 기능을 적용하고 있다면 사용자에게 최대한 투명하게 안내해야 합니다

검색 질의 생성

전달 받은 검색어를 검색 엔진에서 인식하는 query 객체로 변환해야 합니다

→ 질의 생성 절차

QueryParser : 문자열을 Query 객체로 변환해주는 질의 분석 기능

질의로 검색

실제 색인을 뒤져 검색 질의에서 생성한 query 객체에 해당하는 결과를 적당한 정렬 순서에 맞게 받아올 차례입니다

- 정보 검색 분야 3종류의 이론적인 검색 모델

 

1. 순수 불리언 모델

지정된 질의에 문서가 해당하는지 아니면 해당하지 않는지를 판단하며, 별도의 점수 계산 부분은 없음

 

2. 벡터 공간 모델

질의와 문서 모두 고차원 공간의 벡터로 표현한다

벡터 간의 거리를 계산하면 문서와 질의 사이의 연관도나 유사도를 산출할 수 있다

 

3. 확률 모델

확률적인 방법을 통해 개별 문서가 질의와 일치하는 확률을 계산한다

 

루씬에서는

1. 순수 불리언 모델과 2. 벡터 공간 모델을 함께 사용하며,

필요한 경우 검색 시점에 어떤 모델을 사용할 것인지 동적으로 지정할 수 있습니다

결과 출력

이제 검색한 결과로 사용자에게 표현할 결과 문서를 받아옵니다

검색 애플리케이션의 나머지 요소

관리 인터페이스

서버 시작과 종료, 복제 상태 관리, 다양한 검색관련 로그 수집, 검색 시스템의 상황

색인 과정에서 메모리 버퍼의 용량을 지정하거나,

한 번에 병합할 수 있는 세그먼트 개수,

변경 사항을 얼마나 자주 커밋하는지 등

검색 과정에서의 다양한 설정 기능이 API로 준비되어 있습니다

분석 인터페이스

일반적으로 별도 서버에 웹 기반으로 구성

실행된 질의의 종류별 빈도수,

연관도가 낮은 결과를 뽑아 낸 질의

사용자가 결과에서 아무 항목도 클릭하지 않은 질의

연관도 대신 별도의 필드 기준으로 정렬하는 빈도수

루씬에서 검색하는 데 걸린 시간 내역 분석

색인 과정의 작업과 관련된 여러 가지 수치, 예를 들어 초당 색인한 문서 건수 등

시스템 확장

루씬의 색인과 검색 성능을 보면 단일 장비에서 처리할 수 있는 양이 상당합니다

하지만 최소 2중으로 구성해야 합니다

색인을 여러 개의 샤드로 분리해야 하며,

각 장비에서 장비별 샤드를 대상으로 검색해 결과를 취합하게 구성할 수 있습니다

루씬 자체에는 확장성을 지원하는 분산 처리 기능이 들어있지 않습니다

하지만, 엘라스틱서치, 솔라 등에서는 분산 샤드, 색인 복제 등의 기능을 지원합니다

 

색인 관련 핵심 클래스

루씬에서 색인할 때 필요한 클래스

1. IndexWriter

IndexWriter 클래스는 색인 과정에서 가장 중심에 해당하는 클래스입니다

색인을 새로 생성하거나, 기존 색인을 열고 문서를 추가, 삭제, 변경하는 기능을 담당합니다

하지만, 색인의 내용을 검색하거나 꺼내 볼 수는 없습니다

색인을 저장할 공간이 필요합니다

 

2. Directory

루씬의 색인을 저장하는 공간을 나타냅니다

추상 클래스로서 색인을 저장할 공간에 따라 상속받아 필요한 메소드를 구현해야 합니다

다양한 종류의 Directory가 포함되어 있습니다

 

3. Analyzer

텍스트를 색인하기 전에 반드시 Analyzer를 거쳐 단어로 분리해야 합니다

Analyzer 클래스는 Directory와 함께 IndexWriter 클래스의 생성 메소드에 지정합니다

색인할 단위 단어로 분리하고 필요 없는 단어를 제거하는 등의 역할을 담당합니다

추상 클래스로서 루씬 내에는 다양한 종류의 analyzer가 포함되어 있습니다 

ex) 불용어 제거, 대소문자 변환 등

 

4. Document

분석 단계에는 색인할 개별 필드가 담긴 문서가 필요합니다

Document 클래스는 개별 필드의 집합입니다

검색 결과 단위로서, 하나 이상의 Field 객체를 담고 있습니다 (데이터의 내용 또는 메타정보)

 

5. Field

실제 색인할 대상 텍스트는 모두 Field 객체에 담겨있습니다

색인의 각 문서는 모두 2개 이상의 각자 이름이 지정된 개별 필드로 구성되며, 각 필드는 Field라는 클래스로 표현합니다

Document 클래스에는 같은 이름의 필드가 2개 이상 들어갈 수 있는데,

이런 경우 같은 이름의 필드는 Document 객체에 추가된 순서대로 값을 연결해 색인합니다

(즉, 두 필드의 값을 연결 - 하나의 필드를 지정한 것처럼 동작)

 

검색 관련 핵심 클래스

색인 과정과 비슷하게 매우 간단합니다

 

1. IndexSearcher

색인을 담당하던 IndexWriter 클래스처럼 검색을 담당하는 클래스

여러 종류의 검색 메소드를 지원

색인을 읽기 전용으로 열어 사용합니다

예를 들어, 가장 간단한 검색 메소드는 Query 객체와 결과로 받을 문서의 개수 topN을 인자로 지정하고, TopDcos 객체를 결과 넘겨 받습니다

Directory dir = FSDirectory.open(new File("/tmp/index"));
IndexSearcher searcher = new IndexSearcher(dir); // 생성할 때, 이미 색인에 들어있는 Directory 인스턴스를 지정)
Query q = new TermQuery(new Term("contents", "lucene"));
TopDocs hits = searcher.search(q,10); // topN = 10
searcher.close();

 

 

2. Term

Term은 검색 과정을 구성하는 가장 기본적인 단위입니다

필드 이름과 해당 필드에 속한 특정 단어의 쌍으로 이뤄집니다

(Term - 필드 이름 : 특정 단어)

Term 객체도 색인 과정에 관여하지만, Term 객체는 루씬 내부적으로 자동 생성됩니다

검색 시점에는 Term 객체를 직접 생성해 TermQuery 질의를 사용할 수 있습니다

// contents라는 이름의 필드에서 lucene이란 
// 단어를 포함하는 문서중 연관도 기준 내림차순으로 상위 10개의 문서를 찾아오는 기능
Query q = new TermQuery(new Term("contents", "lucene"));
TopDocs hits = searcher.search(q,10);

 

3. Query

루씬에는 Query 클래스를 상속받아 구현한 다양한 종류의 질의 클래스가 포함되어 있습니다

ex) TermQuery, BooleanQuery, PrefixQuery, FilteredQuery 등

Query 클래스는 가장 최소한의 공통부분만 갖고 있는 최상위 질의 클래스입니다

여러 가지 도우미 메소드가 구현되어 있습니다

ex) setBoost(float) : 최종 연관도 점수를 계산할 때 더 높은 점수를 받을 수 있게 가중치 지정

 

4. TermQuery

루씬에서 지원하는 질의 중 가장 기본적인 기능을 가지고 있습니다

특정 필드에 원하는 단어가 들어 있는 문서를 찾아냅니다

 

5. TopDocs

단순히 검색 결과 중 최상위 N개의 문서에 대한 링크를 담고 있는 결과 클래스입니다

최상위 N개의 결과마다 각 문서의 정수형 docID 값과 float 자료형의 점수를 담고 있습니다

 

 

이 글은 “Lucene In Action” 책 내용을 요약한 글입니다.

만약 저작권 관련 문제가 있다면 “shk3029@kakao.com”로 메일을 보내주시면, 바로 삭제하도록 하겠습니다.

댓글