suenjeon 라이브러리 빌드해보기

이 문서에서는 스칼라(자바)로 구현된 형태소 분석기 seunjeon 라이브러리의 빌드 및 사전 업데이트 방법 등을 소개합니다. 중앙 저장소에 공개된 1.5.0 버전에는 자체적으로 사전 데이터가 포함되어 있습니다. 여기서는 라이브러리를 빌드해서 사전 데이터를 외부로 빼내는 과정을 정리합니다.

1. 준비사항

다음과 같은 개발 환경을 준비합니다.

  • Intellij - 소스코드가 scala 로 작성되었고 sbt(scala build tool)로 빌드 작업을 하기 때문에 Intellij(Community Eidition)에서 작업을 진행합니다.
  • ㅇㅇ

1.1. IntelliJ Scala Plugin

IntelliJ를 다운로드하고 설치했다면 scala 개발 설정을 합니다.

메뉴에서 ItelliJ IDEA > Preferences 클릭 후 왼쪽 메뉴에서 Plugins 선택합니다.

Scala 플러그인를 설치합니다.

1.2. Repository Url

seunjeon 저장소 링크

페이지 오른쪽에 [CLONE] 버튼을 눌러서 저장소 주소를 복사합니다.

저장소주소
https://bitbucket.org/eunjeon/seunjeon.git

1.3. New Project

IntelliJ 설치 후 Clone Repository 를 클릭합니다.

Clone Repository
Version Control: [Git] URL : _________________ Directory:

저장소 주소를 URL에 입력하고 [CLONE] 버튼을 클릭합니다.

다음과 같이 seunjeon 저장소를 내려받았습니다.

프로젝트구조
. ├── CONTRIBUTORS.md ├── README.md ├── TODOS.md ├── build.sbt ├── elasticsearch ├── mecab-ko-dic -> mecab-ko-dic-2.0.1-20150920 ├── project │   ├── build.properties │   └── plugins.sbt ├── scripts └── src

2. sbt(build tool for scala)

scala로 작성된 빌드 도구로서 maven이나 gradle과 같은 역할을 합니다.

2.1. sbt 설정 및 소개

[프로젝트구조]에 보면 build.sbt라는 파일이 gradle의 build.gradle에 해당합니다.

빌드에 관여하는 파일은 아래의 3개입니다.

TXT
├── build.sbt ... ├── project │   ├── build.properties │   └── plugins.sbt ...
  • build.sbt - 빌드 절차를 기술함
  • build.properties - sbt 버전(1.0.4)
  • plugin.sbt - 사용할 플러그인 목록. 파일을 열어보면 "com.eed3si9n:sbt-assembly:0.14.6"을 추가했다.

파일을 열어보면 sbt 설정이 없어서 오류가 나오는 상태입니다.

원래는 따로 sbt 를 설치하고 CLI에서 다음과 같이 실행해야 합니다.

sbt
sbt clean package
  • mvn clean package 와 동일함

하지만 IntelliJ에서는 IDE에서 필요한 도구와 환경 설정을 자동으로 제공합니다.

IntelliJ에서 오른쪽 아래쪽에 sbt shell을 클릭합니다.

sbt shell

다음과 같은 prompt를 볼 수 있습니다.

TXT
(initializing)>
  • 설치 중 - 설치 및 초기화에 시간이 걸립니다.

다음과 같은 오류가 나옵니다.

TXT
... [info] Updating {file:/____/seunjeon/project/}seunjeon-build... [info] Done updating. /____/seunjeon/build.sbt:9: error: not found: value useGpg useGpg := true, ^ [error] sbt.compiler.EvalException: Type error in expression [error] sbt.compiler.EvalException: Type error in expression [error] Use 'last' for the full log. Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore?
  • useGpg := true - Maven 저장소에 배포할 때 PGP signing을 하는 듯

seunjeon 개발자가 maven 저장소에 jar 파일을 배포할 때 PGP signing 을 하려고 추가한 듯 합니다.

여기서는 산출물만(jar) 필요하기 때문에 다음의 두 가지 방법 중 하나를 시도합니다.

방법1 주석처리

useGpg:=true 를 주석처리합니다.

주석 처리
publishArtifact in Test := false, // useGpg := true, publishTo := {

방법2 pgp 플러그인 추가

plugins.sbt 파일을 열어서 다음과 같이 sbt-pgp 플러그인을 추가합니다.

TXT
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0")
  • com.jsuereth:sbt-pgp:1.1.0을 추가했음.
  • useGpg를 false로 바꿉니다.

두가지 방법 중 하나를 선택해서 설정을 수정한 후에 sbt shell로 돌아가서 중지시킨 후 다시 shell 을 시작합니다.

sbt shell
[info] Loading settings from idea.sbt ... [info] Loading global plugins from /Users/____/.sbt/1.0/plugins [info] Loading settings from plugins.sbt ... [info] Loading project definition from /Users/____/workspace/ws-scala/seunjeon/project [info] Loading settings from build.sbt ... [info] Loading settings from build.sbt ... [info] Set current project to seunjeon (in build file:/Users/____/workspace/ws-scala/seunjeon/) [IJ]sbt:seunjeon>

sbt shell에서 cleanpackage 명령을 각각 실행합니다.

(sbt shell) clean 명령어
> clean [success] Total time: 1 s, completed Nov 15, 2024 2:44:50 PM [IJ]sbt:seunjeon>
(sbt shell) package 명령어
> package [info] Updating {...}seunjeon... [info] Done updating. [info] Compiling 21 Scala sources and 1 Java source to /____/seunjeon/target/scala-2.12/classes ... [info] Done compiling. [info] Packaging /____/seunjeon/target/scala-2.12/seunjeon_2.12-1.5.0.jar ... [info] Done packaging. [success] Total time: 19 s, completed Nov 15, 2024 2:46:06 PM [IJ]sbt:seunjeon>

다음과 같이 target 디렉토리에 class 파일들과 jar 파일을 빌드했습니다.

산출물
target ├── scala-2.12 │   ├── classes │   │ └── ...class files │   ├── resolution-cache │   └── seunjeon_2.12-1.5.0.jar

하지만 seunjeon_2.12-1.5.0.jar 파일을 살펴보면 파일 용량이 160KB로 매우 작습니다.

Maven 저장소에 등록된 jar 파일은 약 24MB 정도인데 dictionary를 포함하고 있기 때문입니다.

TXT
java/main/resources/dictionalry +- termDict.dat +- dictMapper.dat +- trie.dat ...

2.2. 사전 빌드

DictBuilder.scala 파일에는 사전을 빌드하는 기능이 이미 추가되어 있습니다.

DictBuilder.scala
def main(args: Array[String]): Unit = { clear() copyUnkDef() copyLeftIdDef() copyRightIdDef() println("compiling lexicon dictionary...") buildLexiconDict() println("compiling connection-cost dictionary...") buildConnectionCostDict() println("complete") }
  • src/main/resources/dictionary 안에 사전을 생성합니다.

IntelliJ 를 사용하면 main 메소드를 실행할 수 있는 UI 화면을 제공합니다.

running scala file

버튼을 눌러서 실행하면 다음과 같이 실패합니다.

TXT
Exception in thread "main" java.nio.file.NoSuchFileException: /____/seunjeon/mecab-ko-dic/unk.def at sun.nio.fs.UnixException.translateToIOException(UnixException.java:86) at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102) at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107) at sun.nio.fs.UnixCopyFile.copy(UnixCopyFile.java:526) at sun.nio.fs.UnixFileSystemProvider.copy(UnixFileSystemProvider.java:253) at java.nio.file.Files.copy(Files.java:1274) at org.bitbucket.eunjeon.seunjeon.DictBuilder$.copyDefFile(DictBuilder.scala:82) at org.bitbucket.eunjeon.seunjeon.DictBuilder$.copyUnkDef(DictBuilder.scala:68) at org.bitbucket.eunjeon.seunjeon.DictBuilder$.main(DictBuilder.scala:54) at org.bitbucket.eunjeon.seunjeon.DictBuilder.main(DictBuilder.scala) Process finished with exit code 1

DictBuilder.mainmecab-ko-dic 디렉토리 안에서 사전을 빌드하는데 필요한 .csv, .def 파일을 읽습니다.

TXT
```txt:프로젝트구조 . ├── mecab-ko-dic -> mecab-ko-dic-2.0.1-20150920

mecab-ko-dic 은 symbolic link인데 참조하는 실제 디렉토리가 없습니다.

사전에 신조어를 등록하고 새로 빌드하려면 https://bitbucket.org/eunjeon/mecab-ko-dic 저장소에서 사전 정보를 다운로드해야 합니다.

  • mecab-ko-dic - 사전을 제공함 (2018년도가 최신 버전)

이 기능은 이미 scripts/download-dict.sh에서 제공합니다.

download-dict.sh
... wget -O ${DICT_NAME}.tar.gz "https://bitbucket.org/eunjeon/mecab-ko-dic/downloads/${DICT_NAME}.tar.gz" tar zxvf $DICT_NAME.tar.gz rm mecab-ko-dic ln -sf $DICT_NAME mecab-ko-dic

아래와 같이 실행하면 되는데 다운로드할 사전의 버전을 입력해야 합니다.

사전 다운로드
$ ./scripts/download-dict.sh 사전버전

mecab-ko-dict/downlaod 페이지에서 가장 최근의 사전 이름을 복사합니다.

TXT
mecab-ko-dic-2.1.1-20180720.tar.gz mecab-ko-dic-2.1.0-20180716.tar.gz ...

.tar.gz은 빼고 파일명만 다음과 같이 입력합니다.

사전 다운로드
$ ./scripts/download-dict.sh mecab-ko-dic-2.1.1-20180720

실행 결과

로그
$ ./scripts/download-dict.sh mecab-ko-dic-2.1.1-20180720 Resolving bitbucket.org (bitbucket.org) HTTP request sent, awaiting response... 302 Found ... HTTP request sent, awaiting response... 200 OK Length: 49775061 (47M) [application/x-tar] Saving to: ‘mecab-ko-dic-2.1.1-20180720.tar.gz’ 2024-11-15 15:30:47 (7.72 MB/s) - ‘mecab-ko-dic-2.1.1-20180720.tar.gz’ saved [49775061/49775061]

파일을 다운로드하고 압축을 해제한 후 symbolic link도 수정되었습니다.

사전 구조
├── mecab-ko-dic -> mecab-ko-dic-2.1.1-20180720 ├── mecab-ko-dic-2.1.1-20180720 ├── mecab-ko-dic-2.1.1-20180720.tar.gz
  • mecab-ko-dic 는 2018년도 사전 디렉토리를 링크함.

다시 DictBuilder.main을 실행하면 src/main/resources/dictionary 아래에 사전 파일들이 생성됩니다.

DictBuilder.main 로그
compiling lexicon dictionary... INFO: csv parsing is completed. (191 ms) INFO: terms & mapper building is completed. (800 ms) INFO: added to trie builder (523 ms) INFO: double-array trie building is completed. (21282 ms) building LexiconDict OK. (termSize = 816243 mapper size = 774556) compiling connection-cost dictionary... INFO: connectionDict loading is completed. (25395 ms) building connection cost dictionary OK. (rightSize : 3822, leftSize : 2693, size : 10292648) complete
사전 데이터
src/main/resources/ ├── char.def └── dictionary ├── connection_cost.dat ├── dictMapper.dat ├── left-id.def ├── right-id.def ├── termDict.dat ├── trie.dat └── unk.def