루씬(lucene)은 Java로 작성된 검색 엔진 라이브러리입니다. 검색 엔진을 구성하기 위한 기본적인 모듈을 포함하고 있으며 Elasticsearch, Solr 등 현재 여러 서비스에 사용되고 있는 오픈소스 검색 엔진이 루씬을 사용하여 개발되었습니다.


기본적으로 공식 문서에서는 핵심 용어에 대하여 다음과 같이 정의하고 있습니다.

  • Index(인덱스)는 여러 documents로 구성되어 있고,
  • Document(문서)는 fields의 집합이고,
  • Field(필드)는 terms의 집합이고,
  • Term(용어)는 byte의 집합이다. (같은 byte로 이루어져 있어도 field가 다르면 서로 다른 term으로 간주함)

인덱스는 실제로 데이터를 저장하고 색인 및 검색을 수행합니다.


1. Inverted Index Structure

인덱스에 다음과 같은 형태의 데이터를 입력하였다고 가정합니다.

ID Text
doc1 우, 이번 주 금요일
doc2 금요일에 시간 어때요?
doc3 주말까지 기다리긴 힘들어. 시간아 달려라

단순히 이런 형태로만 계속 저장한다면 데이터가 많아질수록 검색시 어떤 단어가 어디에 위치해 있는지 찾는데 시간이 점점 오래 걸릴것입니다. 따라서 인덱스는 데이터들을 저장할 때 추가적인 작업을 진행하는데, 문자열을 term 단위로 쪼개어 아래와 같은 역인덱스 구조(inverted index structure)에 term과 그 통계 정보를 저장합니다.

Term Frequency Documents
이번 1 doc1
1 doc1
금요일 2 doc1, doc2
시간 2 doc2, doc3
주말 1 doc3

역인덱스 구조는 term을 key값으로 잡고 해당 term에 대한 통계 정보를 저장하고 있습니다. 이런 데이터 구조 덕분에 루씬은 term 기준으로 문서를 빠르게 검색할 수 있습니다. 두꺼운 책의 맨 뒤 “찾아보기” 와 비슷한 원리라고 생각하면 좋습니다.


2. Analyzer

Analyzer는 문자열을 검색 가능한 토큰으로 분해하는 형태소 분석을 수행합니다. 형태소 분석 과정에서 색인 및 검색 프로세스에서 사용되는 TokenStream을 생성합니다. 하나의 tokenizer와 여러 filter로 이루어져 있는데, CharFilter → Tokenizer → TokenFilter 순으로 작업을 진행합니다.

  • CharFilter : Tokenize 과정을 진행하기 전에 불필요한 문자들을 제거합니다. 대부분의 Analyzer는 Tokenizer를 처음 순서로 구성하지만, 필요에 따라 그 이전에 CharFilter를 두어 사전에 텍스트를 필터링하는 경우도 있습니다.
  • Tokenizer : 입력받은 문자열을 토큰으로 분해합니다.
  • TokenFilter : Tokenizer가 분해한 토큰을 추가적으로 조정하는 작업을 하는데 Analyzer의 필수 요소는 아닙니다. 필요한 경우 문자 제거, 어간 추출, 동의어 처리, 대소문자 처리 등을 수행합니다.

References