본문 바로가기

Computer Science/DB

Elasticsearch 한국어 형태소 분석기의 원리 - 1

elasticsearch에 관해 학습했던 내용을 정리한 내용입니다. 혹시 잘못된 내용이 있으면 편하게 지적부탁드립니다.

 

서론

검색은 어떻게 이루어질까요?

 

RDB에서 데이터를 조회할 때, 빠르게 검색하기 위해 인덱스를 사용합니다. 한국어로 색인이라고도 부르는 이 개념은, 예를 들어 ‘햄버거’라는 데이터를 빠르게 찾으려면 해당 데이터가 포함된 위치를 가리키는 색인을 이용해 검색 속도를 높이는 방식으로 작동합니다.

 

반면, Elasticsearch는 역인덱스(inverted index)라는 방식을 사용하여 데이터를 저장합니다. 역인덱스는 특정 키워드와 관련된 문서의 위치 목록을 저장하는 구조로, 검색 시 특정 키워드와 연관된 문서들을 빠르게 찾을 수 있도록 설계되었습니다. 이 방식은 검색 엔진의 핵심적인 데이터 구조로, 텍스트 기반 검색에서 특히 강력한 성능을 발휘합니다.

 

Elasticsearch에서 데이터의 최소 단위는 문서(document)입니다. 문서들은 인덱스(index)라는 이름의 논리적 구조에 저장되며, 각 인덱스는 여러 문서를 포함합니다. Elasticsearch에 데이터를 저장(색인)하기 위해서는 매핑(mapping) 정보가 필요합니다. 매핑은 각 필드가 어떻게 저장되고 처리될지를 정의하는 설정입니다.

 

이 과정에서 토크나이저(tokenizer)라는 개념이 중요한 역할을 합니다. 토크나이저는 입력된 텍스트 데이터를 처리하여 검색 가능한 형태로 분리하는 도구입니다. 예를 들어, 문장을 단어 단위로 쪼개거나 특정 규칙에 따라 텍스트를 나누는 작업이 여기에 해당합니다. 이 글에서는 Elasticsearch, 좀 더 구체적으로 AWS Opensearch에 한정하여 토크나이저의 개념과 동작 방식을 중심으로 그 활용 사례를 살펴보겠습니다.

 

토크나이저란?

 

Opensearch 공식 문서에서는 토크나이저를 다음과 같이 정의합니다.

A tokenizer receives a stream of characters, breaks it up into
individual tokens (usually individual words), and outputs a stream of tokens.

 

즉, 토크나이저는 문자 스트림을 입력으로 받아 토큰 단위로 쪼개어 토큰 스트림으로 변환하는 도구입니다. 여기서 토큰이란 일반적으로 단어, 기호, 문장 부호와 같은 단위로 정의됩니다. 

 

 

위 이미지에서 Quick green frog라는 문장을 입력으로 받았을 때, 출력으로 [Quick, green, frog]를 반환하는 토크나이저를 생각할 수 있습니다.

 

그런데 어떤 기준으로 토큰으로 쪼개야할까요?

 

토크나이징 방식에는 다음과 같은 방법이 있을 수 있습니다.

 

 

심볼 단위 토크나이징

가장 단순하게는 음절 등의 단위로 묶을 수 있겠습니다.

  • unigram : 1개의 심볼이 하나의 토큰
  • bigram : 2개의 심볼이 하나의 토큰
  • ngram : n개의 심볼이 하나의 토큰
  • edge-ngram : edge에서부터 n개의 심볼이 하나의 토큰

심볼단위 토크나이징의 예시

 

 

형태소 단위 토크나이징

또 다른 방법으로는, 형태소 단위 토크나이징입니다.

 

형태소란, 국립국어원에서 다음과 같이 정의합니다.

형태-소 (形態素)
「명사」『언어』
「1」뜻을 가진 가장 작은 말의 단위. ‘이야기책’의 ‘이야기’, ‘책’ 따위이다.
「2」문법적 또는 관계적인 뜻만을 나타내는 단어나 단어 성분. ≒형태질「2」.
<국립국어원 표준국어대사전>

 

즉, 의미를 가지는 단위인 형태소 단위로 토큰을 나누는 것인데요,

형태소를 어떻게 빠르게 식별하고 형태소 기준으로 쪼갤 수 있을까요?

 

영어라면 가장 단순하게 공백을 기준으로 토크나이징한다고 해도(standard tokenizer) 꽤 의미있는 토큰들을 얻을 수 있습니다.

반면 한국어는 언어적인 특성에서 기인하는 어려운 점들이 있는데요, 한국어의 형태론적 특성의 예는 다음과 같습니다.

(예시는 은전한닢의 자료를 참고하였습니다.)

 

교착어

하나의 실질형태소에 여러 개의 문법형태소가 붙어 단어를 만든다.

예: ‘행복하셨겠습니다' -> ‘행복하'실질형태소, ‘셨'높임, ‘겠'과거, ‘습니다'높임

 

형태론적 중의성

형태소 분리와 품사 중의성

예: ‘보고서’ -> ‘보고서’체언, ‘보’용언 + ‘고서’어미

 

형태론적 변형

용언의 불규칙 활용

아름답다 -> 아름다워

탈락과 축약

보아 -> 봐

 

비구조적(non-configurational) 언어

어순이 비교적 자유로움 

 

이중 주어

이 책 구내서점 100원이 싸다.

 

주어 생략

(내가) 밥을 먹고 (내가) 학교에 가서 (내가) 강의를 들었다.

 

격조사 생략

밥(을)먹고 시청 앞(의) 분수대에서 응원(을)했다.

 

준말과 축약

그러기에 -> 그러하기 때문에

그렇지만 -> 그렇지마는 -> 그러하지마는

 

이렇듯 복잡한 규칙을 가지고 있기 때문에,

언어학적 규칙과 수많은 예외사항을 기반으로 규칙 기반으로 동작하는 형태소 토크나이저를 만들기 어렵습니다.

 

또한, 이를 만든다고 해도 언어는 자의적이고, 사회적 약속이라는, 그리고 시간에 따라 언어도 변한다는 특징때문에,

시간에 따라 언어가 변한다해도 형태소 분석기도 계속해서 변해야하는지라는 의문이 남습니다. 

 

이런 어려움 때문에 등장한 개념이 확률론적 모델링인데요,

간단히 말하자면 '언어의 특성과 규칙에 상관없이 확률적으로 가장 말이 되는 조합으로 쪼개자'라는 개념이 등장하게됩니다.

 

이렇게 했을 때 장점은 다음과 같습니다.

  • 확률적 모델링을 하면 언어에 독립적이다.
  • 한국어의 무수히 많은 문법적 규칙을 분석할 필요가 없다.
  • 사용하는 말뭉치(사전)만 바꾸면 된다.

확률론적 모델링을 하기 위해서는 많은 학습 데이터가 필요합니다.

 

한글 형태소 분석기의 학습 데이터는 어디에서 왔을까요?

 

한글 형태소 분석기와 학습 데이터의 출처

 

21세기 세종 프로젝트는 1998년부터 2007년까지 약 10년 동안 진행된 한국의 국어 정보화 중장기 발전 계획입니다.

이 프로젝트의 주요 목표 중 하나는 대규모 한국어 말뭉치를 제작하는 것이었습니다.

말뭉치는 사람들이 일상적으로 사용하는 말이나 글을 컴퓨터가 읽을 수 있는 형태로 모아 놓은 언어 자료를 말합니다.

이 프로젝트를 통해 생성된 말뭉치는 한국어 형태소 분석기를 포함한 다양한 언어처리 시스템의 근간이 되었으며, 오늘날 대부분의 한국어 형태소 분석기가 이 데이터를 사용하고 있습니다.

 

세종 말뭉치의 구성

  • 문어 말뭉치 · 원시 말뭉치: 약 3,700만(36,879,143어절) 
  • 형태 분석 말뭉치: 약 1,000만(10,066,722어절)
  • 의미 분석 말뭉치: 약 1,000만(9,071,054어절)
  • 구문 분석 말뭉치: 약 45만(433,839어절, 43,828문장)

세종 말뭉치 기반으로 학습된 데이터는 형태소 분석을 위한 표준 자료로 사용되며, 이를 통해 한국어 자연어 처리 기술이 발전해 왔습니다.

세종 말뭉치를 기반으로 한 학습 데이터의 예시는 다음과 같습니다.

 

표층형 품사 태그 의미 부류 종성 유무 읽기 타입 첫번째 품사 마지막 품사 표현
태양 NNG * T 태양 * * * *
서울 NNP 지명 T 서울 * * * *
불태워졌 VV+EM+VX+EP   T 불태워졌 Inflected VV EP 불태우/VV/*+어/EC/*+지/VX/*+었/EP/*
해수욕장 NNG   T 해수욕장 Compound * * 해수/NNG/*+욕/NNG/*+장/NNG/*

 

품사, 종성 유무, 타입, 분리된 단어의 품사 등의 정보를 품고 있으며 이 정보를 학습해 적절한 형태소 분석을 하는 모델을 생성하게 됩니다.

 

한국어 형태소 분석기 탄생의 역사

 

앞서 설명한 세종 말뭉치는 한국어 형태소 분석기의 학습 데이터로 널리 사용되며, 이를 기반으로 여러 형태소 분석 엔진이 개발되었습니다.

그중 대표적인 엔진으로는 Mecab과 이를 활용한 은전한닢, nori와 같이 잘 알려진 다양한 프로젝트들이 있습니다. 놀랍게도 mecab은 일본어 형태소 분석을 위해 설계된 분석 엔진입니다.

 

Mecab

Mecab은 일본어 형태소 분석을 위해 설계된 오픈 소스 형태소 분석 엔진

mecab-ko-dic

Mecab-ko-dic은 Mecab 엔진에 세종 한글 말뭉치의 일부 데이터를 활용해 한국어에 맞춰 개발된 형태소 분석 사전

Mecab-ko(Seunjeon)

Mecab-ko는 Mecab 엔진에 세종 말뭉치 데이터를 추가적으로 적용하여 한국어 문장 구조를 더욱 정확히 분석할 수 있도록 설계된 프로젝트

Nori

Nori는 Elasticsearch에서 한국어 형태소 분석을 위해 개발된 독자적인 엔진입니다. 일본어 형태소 분석 엔진인 Kuromoji의 코드를 포크(fork)하여 Mecab-ko-dic 사전을 적용

 

위 내용을 요약하면 다음과 같습니다.

학습 데이터 사전 학습 모델 사전 형태소 분석 모델 형태소 분석기
일본 말뭉치 Mecab IPADIC kuromoji kuromoji
한글 말뭉치 mecab-ko-dic mecab seunjeon
kuromoji nori

 

 

Elasticsearch의 독자적인 한국어 형태소 분석기 Nori는 Lucene에서 제공하던 일본어 분석기를 기반으로 탄생했습니다. Lucene은 3.6 버전부터 Mecab을 사용하는 일본어 형태소 분석기를 포함하고 있었으며, 이를 기반으로 메모리 사용량과 속도를 최적화한 Nori를 개발하게 되었습니다. Elasticsearch 공식 블로그는 이러한 배경을 다음과 같이 설명하고 있습니다.

두 사전 모두 같은 도구로 만들었기 때문에, 루씬의 일본어 분석기를 재사용해서 이 한국어 사전을 처리하는 것은 구미가 당기는 일이었습니다. 이 방법의 장점은 여러 해에 걸쳐 메모리 사용량과 속도 면에서 최적화된 견고한 분석기를 활용할 수 있다는 점입니다. 이렇게 해서 “노리”가 탄생했습니다.

 

이처럼 Nori는 일본어 형태소 분석기의 견고함과 최적화된 성능을 재사용하면서도, 한국어의 언어적 특성에 맞게 커스터마이징되어 Elasticsearch에 특화된 형태소 분석기라고 할 수 있겠습니다.

 

 

nori와 은전한닢, 뭘써야하지?

여기까지 읽으셨다면 그래서 뭘 써야하는지 궁금하실 것 같습니다. 저 역시도 실무에서 nori와 은전한닢 중 어떤 토크나이저를 적용해야 더 빠르게 정확한 결과를 얻을 수 있을 지 궁금했습니다. elasticsearch 공식 블로그에서 nori와 기존 프로젝트와의 차이점과 벤치마크 결과를 정리해두어 여기에 간단히 소개합니다. 

 

먼저, 은전한닢과 nori는 똑같은 사전(Mecab-ko-dic)을 사용하지만 더 가볍습니다.

은전한닢과 Nori는 동일한 Mecab-ko-dic 사전을 사용하며, 원본 사전의 크기는 약 200MB에 달합니다.

Nori는 사전 용량을 약 88% 감소시키면서도 동일한 데이터를 유지하는 데 성공했습니다.

 

어떻게 최적화 했는지에 대한 설명은 다음과 같습니다.

 

1. 파일 형식 변환

Mecab-ko-dic 사전은 기본적으로 .csv 파일로 제공됩니다.

Nori는 이를 .dat 형식의 바이너리 파일로 변환하여 읽기 속도를 향상시키고 메모리 사용량을 줄였습니다.

2. 중복 데이터 최소화

말뭉치에서 단어 예시 [대학]이 여러 번 출현할 때, 문자열을 숫자 형태로 부호화하여 중복을 줄였습니다.

3. 자료형 변환

숫자 필드(예: 문맥 ID, 비용)를 효율적으로 저장하기 위해 int 자료형을 short로 변환하여 저장 공간을 절약했습니다.

 

이로인한 더 빠른 인덱싱 벤치마크 결과입니다. (출처: elasticsearch 블로그)

결론적으로, Nori는 뛰어난 사전 최적화와 Elasticsearch에 특화된 성능으로 더 나은 선택지가 될 가능성이 큽니다. 

 

다음 글에서는 Mecab 엔진의 형태소 분석 원리를 좀 더 깊이 알아보는 내용을 써보겠습니다.

 

참고자료

어떤 한국어 분석기를 사용할까? – elasticsearch 공식 블로그

https://www.elastic.co/kr/blog/using-korean-analyzers

 

공식 한국어 분석 플러그인 “노리” – elasticsearch 공식 블로그

https://www.elastic.co/kr/blog/nori-the-official-elasticsearch-plugin-for-korean-language-analysis

 

Elastic Seoul Meetup – JM.Kim – 6.3 release & nori analayzer

https://www.youtube.com/watch?v=80WiaOdnjXU

 

은전한닢 프로젝트 – 형태소 분석기 프레젠테이션

https://docs.google.com/presentation/d/1qhuhi7A-4XF0X4DVJrSIjKbtMYO9Fh09czpL0mheGjg/edit#slide=id.p

 

Nori, a Korean analyzer based on mecab-ko-dic

https://issues.apache.org/jira/browse/LUCENE-8231

 

21세기 세종 말뭉치 살펴보기

https://www.korean.go.kr/nkview/nklife/2016_2/26_0204.pdf

 

일라스틱서치 공식 가이드

https://www.elastic.co/guide/en/elasticsearch/reference/current/analyzer-anatomy.html

 

MeCab: Yet Another Part-of-Speech and Morphological Analyzer

https://taku910.github.io/mecab/