본문으로 바로가기
반응형

영어와 같이 단어가 공백단위로 분리된다면야 tokenizing 하기가 쉽겠지만 제가 아는 아시아 언어들은 띄어쓰기만으로 tokenize를 하면 제대로 term을 만들기 쉽지 않습니다.

물로 영어도 단어의 원형, 동사의 원형으로 변환하는 과정을 거쳐야 하겠지만, 한글이나, 일어(일어는 띄어쓰기가 없는걸로 알고 있습니다만..)등의 언어는 공백으로 분리해서 만들어진 term으로는 검색효율이 떨어집니다.

"사과와 포도는 참 달다""사과와" "포도는" "참" "달다" 분리했을때 "사과"로 검색하면 검색결과가 0이겠죠~

N-Gram 분석기는 글자를 한글자씩 연결해 가면서 term을 생성하는 방법을 말합니다.


이 글은 lucene v8.2.0 기준으로 작성되었습니다.

모든 예제코드는 Kotlin으로 작성되었습니다.

N-Gram Analyzer

N-Gram은 문장을 한글자씩 잘라가면서 n개만큼씩 붙여서 term을 만듭니다.
"사과와 포도는 참 달다"

-> N=2
"사과" "과와" "와" "포" "포도" "도는" "참" "달" "달다"

-> N=3
"사과와" "과와" "와 포" "포도" "포도는" "도는 " "는 참" "참" "참 달" "달다"

문장을 한글자씩 쪼개서 N개 단위로 붙여서 term을 만듭니다.


N=2일때 "사과"는 검색이 되겠지만 N=3일때는 안될수 있겠죠?

이렇게 검색되는 확률은 높일 수 있지만 누락되는 검색도 생기고 쓰잘데기 없는 term들도 생깁니다.

따라서 검색어를 자르는 용도보다는 특정 패턴을 검색하는데 사용됩니다.


class NgramAnalyzer : Analyzer() {
    override fun createComponents(fieldName: String): Analyzer.TokenStreamComponents {
        val tokenizer = NGramTokenizer(2, 2)
        val nGramTokenFilter = NGramTokenFilter(tokenizer,2)
        return Analyzer.TokenStreamComponents(tokenizer, nGramTokenFilter)
    }
}

위와 같이 Analyzer를 만들어 사용하면 됩니다.

NGramTokenizer 생성시 넣는 param값은  min N, max N 입니다.

만약 NGramTokenizer(2,3)으로 만들면 N=2, N=3 일때의 term을 모두 만듭니다.


한글 분석기

언어별로 단어의 변화는 모두 다르기 때문에 언어별로 Analyzer를 특화시켜서 사용해야 합니다. (하지만 쉬운일이 아니겠죠.)
다행이 루씬에서는 여러 언어용 analyzer를 제공하기 때문에 해당 언어에 따라 Analyzer를 선택하여 사용하면 됩니다.
한글 역시 은전한닢, 꼬꼬마분석기등이 존재하며, lucene 7.4.0 부터 nori 분석기가 포함되었습니다.

한글 분석기는 문장을 형태소로 쪼개어 term을 생성합니다.

maven의 경우 pom.xml에 위와 같이 dependency를 걸어 줍니다.

열어보면 Analyzer와 여러 filter, tokenizer가 보이네요.

사용은 new KoreanAnalyzer()로 생성하여 사용하면 됩니다.

반응형