OpenSearch 형태소 분석 Test Case 만들기

임용근
Spoonlabs
Published in
15 min readJul 10, 2024

안녕하세요.

스푼라디오 Business Platform Team의 임용근(Whale)입니다.

팀내에서는 활발히 포스트 작성을 앞다투어 하시는데, 저는 오랜만에 작성을 하는 것 같습니다.

이번 포스트는 SpoonRadio에서 OpenSearch의 은전한닢 형태소 분석을 이용한 Application(이하 Search Manager)에서 Test Case 를 어떻게 구성는지 소개 하고자 합니다.

형태소 분석 확인은 OpenSearch의 /_analyze 를 통해 확인하면서 설정을 할 수 있습니다만, 실제 OpenSearch에 검색을 요청하는 Search Manager에서는 형태소 분석이 되었는지 알수가 없고, Test Case 구현 시 형태소 분석이 되었다고 가정하에 만들 수 밖에 없습니다.

따라서 Search Manager에서도 OpenSearch 에 실제로 검색을 실행하면서 테스트를 진행해야 하는데 사소한 어려움이 있네요

AWS OpenSearch에는 다양한 국가별 Analysis를 지원하는데, 한국어는 은전한닢(seunjeon)을 지원하고 있습니다.

한국어 형태소 분석기를 이용하여 개발 할 당시(2023년 초)에는 은전한닢밖에 없어서 아쉬웠는데, 2023년 10월부터 Nori를 포함하여 다른언어 분석기도 지원한다고 하네요.
(Amazon OpenSearch Service, 4개의 새로운 언어 분석기에 대한 지원 추가 )

은전한닢 VS NORI

저는 ElasticSearch를 학습하기 시작할때에는 ‘은전한닢’을 사용해왔으나, ElasticSearch 6를 접하면서부터 Nori를 사용하기 시작했습니다.

어느것이 좋다/나쁘다를 논하기에는 제 실력이 미천하여 언급하기가 어려운데, 설정이 간편하다는 이유로 조금이라도 눈이 가는건 Nori 입니다.

지극히 개인적인 의견이며, 수치상의 어떠한 지표는 사실 100% 체감하지 못해서 개인적으로 의미를 두진 않습니다.

비교내용이 잘 정리 된 블로그는 구글에 검색하면 많은 정보를 찾아보실 수 있습니다. (은전한닢 Vs NORI — Google Search )
(혹은 ChatGPT에 물어보면 자세히 설명해 줍니다.)

이 포스트에서 설명하고자 하는 내용은 형태소 종류에 대한 성능이나 장단점 등이 아닌, 형태소 분석기를 탑재한 OpenSearch Docker Container(이하 Container)를 Test Case 작성 시 어떻게 진행하는가에 대한 내용이므로, 은전한닢 혹은 Nori 선택은 자유롭게 하시면 되겠습니다.

다만, 은전한닢의 경우 Plugin 설치과정이 조금 복잡하여, 정리한 내용으로 생각해주시면 되며, Nori (그외 plugin 간편설치가 가능한 분석기)를 사용하시는 분들은 ‘Image 만들기’ 부터 보시면 좋을 것 같습니다.

그럼 시작 하겠습니다.

AWS의 OpenSearch의 환경 구성을 할 경우, 보통은 은전한닢 형태소 분석기(이하 은전한닢)는 기본적으로 설치가 되어있을 겁니다.

AWS OpenSearch Plugins

하지만, Application 개발단계에서 테스트를 진행할경우 Container를 통해 OpenSearch를 기동하게 되면, 은전한닢을 포함하여 언어관련 Analysis 가 누락된것을 볼 수 있습니다. (OpenSearch Container Download)

OpenSearch 1.3.2 Container plugins Logs

그렇다면 Application Test Case 작성 중 , Container에 형태소가 없을때 어떤 문제가 생기는 것 일까요?

예를들어 검색 대상이 되는 Field가 있고, “스푼라디오”라는 키워드를 은전한닢 tokenizer로 분석 했을 때 색인어가 “스푼” 과 “라디오”로 분리되어 검색이 되어야 합니다. (원하는 분석결과)

하지만, 테스트 진행 시 은전한닢 tokenizer가 없다면 Field의 색인어는 “스푼”과 “라디오”라고 분리가 되었을 것이다~ 라고 추측하여 테스트가 이루어져야 합니다.
즉, 형태소 분석이 아닌 다른 방법으로 강제로 분리된 상황을 만들어 주어야 할 것입니다. (예를들어 ngram같은 도구로 token을 생성해야함)

위와 같이 강제로 token을 만들어 어떻게든 테스트를 통과 시킬 수는 있겠으나, 테스트 통과가 목적이 아닌 Repository 데이타와의 정합성에 포커스를 맞춘다면 Repository의 scheme 또한 정확하게 설정 되어있어야 할 것입니다.
(Database 테스트를 진행 할때에도, Table scheme을 맞추듯이 말이죠.)

즉, Search Manager기능에 대해 정확한 테스트가 진행되기 위해서는 OpenSearch Container에 형태소 분석이 필수가 되어야 할 것 입니다.

OpenSearch 1.3.12 버젼의 Container로 테스트 진행 결과, “seunjeon_tokenizer” 에러 발생

그럼 은전한닢 plugin은 어떻게 설치를 할까요?

다행히도 OpenSearch Container의 HOME/bin에는 opensearch-plugin 라는 plugin 관리 툴이 존재합니다.

plugin을 설치할 수 있는 도구이고, 이를 이용하여 Container 내에 plugin을 설치가 된다면 위 에러를 해결할 수 있을 것 같습니다.

다만, 위에서 살짝 언급했듯이, 은전한닢 이외 플러그인 설치는 간단하므로, “Image 생성하기” 부터 보셔도 됩니다.
(은전한닢 간편설치 아시는분 계시면 댓글로 지적 부탁드리겠습니다!)
(OpenSearch 플러그인)

Plugin 설치

은전한닢을 설치하기 위한 순서는 아래와 같으며, 하나씩 진행해보도록 하겠습니다.

  1. 은전한닢 다운로드 및 패키징
  2. 패키징파일(zip)을 OpenSearch Container로 복사 및 plugin 설치
  3. OpenSearch Container Restart

1. 은전한닢 다운로드 및 패키징

  • 은전한닢은 ElasticSearch용과 OpenSearch용 별도로 존재하고 있는 듯 합니다.
    > OpenSearch for seunjeon — Bitbucket
    > Git 으로 받으시는거.. 잘 아시죠? 😀 (설명 생략)
  • 사전 다운로드
    > eunjeon/mecab-ko-dic (이 포스트에서는 최신 버전으로 다운로드 하였습니다. 2.1.1–20180720)
    > OpenSearch HOME으로 다운로드 받아, 압축을 해제합니다.
  • 패키징 진행
> sbt -J-Xmx2G "runMain org.bitbucket.eunjeon.seunjeon.DictBuilder"
...
complete

> sbt
sbt:seunjeon-OpenSearch> project OpenSearch
[info] 블라블라~

sbt:OpenSearch-analysis-seunjeon> OpenSearchZip
...
[info] Done packaging
[success] 블라블라

결과

패키징 완료 화면

패키징 파일을 확인해 보겠습니다.

은전한닢 HOME> cd ./opensearch/target
은전한닢 HOME/opensearch/target> ls -al

drwxr-xr-x 8 whale staff 256B 7 4 18:33 ..
-rw-r--r-- 1 whale staff 14B 7 4 18:33 .history
drwxr-xr-x 3 whale staff 96B 7 4 18:33 classes
-rw-r--r-- 1 whale staff 32M 7 4 18:34 opensearch-analysis-seunjeon-assembly-1.0.0.jar
-rw-r--r-- 1 whale staff 30M 7 4 18:37 opensearch-analysis-seunjeon-assembly-1.3.12.zip
-rw-r--r-- 1 whale staff 221B 7 4 18:36 plugin-descriptor.properties
drwxr-xr-x 4 whale staff 128B 7 4 18:33 resolution-cache
drwxr-xr-x 5 whale staff 160B 7 4 18:33 streams

plugin 정보입력 과정에, plugin-descriptor.properties 파일 내용중 opensearch.version 이 정상적으로 들어가지 않은 경우가 있습니다.
(script를 수정하면 되겠지만 딱~ 한번만 사용할 것이니, properties만 수정하도록 하겠습니다.)

1.0.0 을 1.3.12 (OpenSearch Version)으로 수정

기존의 zip 파일은 삭제 후, jar 파일과 properties를 zip으로 압축합니다.

은전한닢 HOME/opensearch/target> rm opensearch-analysis-seunjeon-assembly-1.3.12.zip
은전한닢 HOME/opensearch/target> zip opensearch-analysis-seunjeon-assembly-1.3.12.zip plugin-descriptor.properties OpenSearch-analysis-seunjeon-assembly-1.0.0.jar

위 흐름대로 진행 할경우, 문제가 없었다면 다행이지만, 저는 두가지 문제가 발생하여 살짝 언급 하고 넘어가겠습니다.

SBT 에러 상황 (1)

...
[info] Done compiling.
/Users/whale/Desktop/custom-es/seunjeon-OpenSearch/build.sbt:9: error: not found: value useGpg
useGpg := true,
^
...

위와 같은 에러가 발생할경우, build.sbt 에서 해당항목을 삭제하면 됩니다.

9번 Line 제거

GNU PG란

GNU PG란?
> GNU PG는 이메일을 암호하/서명하는데 널리 쓰이는 오픈소스 보안 소프트웨어
> Local Test용이기 때문에, 굳이 필요치 않을 것 같습니다.
> 그래도 찝찝하시면 gpg를 설치하셔서 해결 하시면 됩니다.

SBT 에러 상황 (2)

mecab 관련 파일존재하지 않는 에러가 나올 수 있으므로, 조금전 다운로드 받은 mecab 으로 연결 해주면 됩니다.

> rm -rf mecab-ko-dic
> ln -s mecab-ko-dic-2.1.1-20180720 mecab-ko-dic

# 혹은 압축해제 한 디렉토리의 이름변경
> mv mecab-ko-dic-2.1.1-20180720 mecab-ko-dic

2. 패키징파일(zip)을 OpenSearch Docker에 복사 및 plugin 설치

# Container로 파일 복사
> docker cp OpenSearch-analysis-seunjeon-assembly-1.3.12.zip [CONTAINER ID]:/usr/share/opensearch

# Container로 접속
> docker exec -it [CONTAINER ID] sh
Ru
# Plugin 설치
> ./bin/opensearch-plugin install file:///usr/share/opensearch/opensearch-analysis-seunjeon-assembly-1.3.12.zip

혹은 다른 analysis가 필요하시면 간편설치로 진행하셔도 됩니다.

# nori / kuromoji 설치
> ./bin/opensearch-plugin install anaysis-nori anaysis-kuromoji 등등~
plugin 설치 과정

3. OpenSearch Container Restart

# plugin 설치 후, 다시 시작
> docker restart [CONTAINER ID]

# OpenSearch 기동 log 확인
> docker logs -f [CONTAINER ID]
plugins 로드 확인

Plugin 설치 성공입니다~

IMAGE 만들기

Plugin을 정상적으로 설치하였고, Container 실행까지 완료 되었습니다.

이제 Plugin이 포함 된 새로운 Image로 생성후, Application에서 사용할 수 있도록 작업을 진행해야할 것 같습니다.

이미지 생성하기

> docker commit -a "whale" -m "spoon radio OpenSearch(with seunjeon-analysis)" whale-open whale-opensearch:seunjeon

잠깐만!

  • 이미지 생성은 Dockerfile 을 작성하여 build 하는 방법을 추천합니다.
  • 생성된 이미지는 Local에만 존재 하기 때문에 이미지 공유가 가능한 Respository (Docker hub 같은..) 등에 올려두어 사용하십시오.
  • 본 포스트에서는 Docker 이미지 관련된 내용은 작성하지 않으므로 양해 바랍니다

IMAGE 생성 확인하기

예쁘게 잘 만들어졌습니다.

그럼, 새로 생성한 이미지를 이용하여, 위 에러가 발생한 Test Cast를 다시 실행해보겠습니다.

Test Container DockerName을 “opensearchproject/opensearch:1.3.12" 에서 “whale-opensearch:seunjeon"로 변경합니다.

DockerName 변경

성공하는 결과를 볼 수 있습니다.

초록색은 언제나 짜릿해! 🤩

이제부터 Test Container에서 은전한닢을 사용할 수 있는 조건이 되었습니다.

그렇다면, AWS OpenSearch에 적용한 설정으로 테스트 해봐야 할텐데요,
실제 사용하는 Settings은 보안상 포스트에 넣지 못했으나, 일부 수정하여 진행해보도록 하겠습니다.

아래는 포스트 작성을 위해 임의로 작성한 Settings 입니다.

{
"settings": {
"index": {
"analysis": {
"analyzer": {
"korean_analyzer": {
"filter": [
"lowercase"
],
"type": "custom",
"tokenizer": "seunjeon_default_tokenizer"
}
},
"tokenizer": {
"seunjeon_default_tokenizer": {
"index_poses": [
"UNK","N","SL","SH","SN"
],
"max_unk_length": "20",
"pos_tagging": "false",
"index_eojeol": "false",
"decompound": "true",
"type": "seunjeon_tokenizer",
"deinflect": "true"
}
}
}
}
},
"mappings": {
"properties": {
"field": {
"type": "text",
"analyzer": "korean_analyzer"
}
}
}
}

Test Case 실행 결과

원하는대로 테스트가 진행 됨.

Test Case상에서 검색대상 Field에 “스푼라디오”라는 키워드가 입력 되었고, OpenSearch에서 은전한닢으로 분석 된 색인어(“스푼”, “라디오”)에 대해 “라디오”로 검색 후 결과가 정상적으로 출력 되는 것을 볼 수 있습니다.

지금까지의 내용을 통합하여 실제 Search Manager에서 많은 Test Case를 작성하였고, 그에 따른 결과물입니다.

Search Manager에서의 Test Case 결과

마치며

어떻게 보셨나요?

간혹 사소하다 생각되는 부분때문에 어떠한 일이 진행이 되지 않을때가 있는 것 같습니다.

이 포스트 내용도 비슷한 느낌으로 진행했던 부분인데, 이후에 조금이나마 남아있던 찝찝함(?)을 해소하고, OpenSearch의 settings가 수정 되었을때 검색 결과 및 Application 기능에도 영향을 미치기 때문에 전반적으로 테스트를 진행 할 수 있어, 개인적으로 너무 만족스러운 작업이었습니다.

(현재 스푼라디오의 검색파트는 한국어/일본어/중국어를 위와같은 방법으로 Test Case 를 만들어나가고 있습니다.)

어떻게 보면 대단한 내용도 아니고 매우 당연한 과정일 수 있겠으나, 여러가지 시행착오를 통해 완성되니 뿌듯한 마음에 포스트를 작성해보았습니다.

진행에 많은 도움 주신분들께 감사드립니다.

Architecture Team — Danny
Data Tech Team — David
Business Platform Team — Sam / Joe

--

--