DockerのElasticsearchにSudachiをみっちり入れる

目的

前回は、SudachiをElasticsearchに入れるシンプルなやり方を紹介しました。

tsgkdt.hatenablog.jp

しかし、ダウンロードURLが変わったらどうすんの?バージョン文字列ならまだしも、いつ変わるか分からない文字列を持ちたくないです!という人もいらっしゃるでしょうし、 pom.xmlがあるんだから自分でビルドするがな! という奇特な方もいると思います。

今回はそんな方向けの情報です。

やること

必要な資源は3つなのは変わりません。

  1. Elasticsearch
  2. Sudachiの辞書
  3. elasticsearch-sudachiのプラグイン

ですが、これをSudachiに関しては、すべてGithubからソースを落としてきてビルドしましょう。

マルチステージで並列ビルドさせます。

f:id:tsgkdt:20190409225355p:plain
multi stage build

辞書を生成するのと、elasticseaerch-sudachiプラグインは互いに独立した処理にできます。 辞書には、sudachiのjarが必要なので、sudachiのjarを作るところから入ります。

結論

Dockerファイルをあげておきましょう。
原本は以下に置いてあります。

https://github.com/tsgkdt/elasticsearch-sudachi-docker/blob/master/Dockerfile

# syntax = docker/dockerfile:1.0-experimental

ARG ELASTIC_VER=6.7.0
ARG ELASTIC_SUDACHI_VER=${ELASTIC_VER}-1.3.0
ARG SUDACHI_VER=0.2.1


######################################################################
# Sudachi本体のビルド. 辞書ビルドで、このjarが必要になる
######################################################################
FROM maven:3-jdk-8 as sudachi
RUN --mount=type=cache,target=/root/.m2 \
    git clone https://github.com/WorksApplications/Sudachi.git && \
    cd Sudachi && \
    mvn package -Dfile.encoding=UTF-8 

######################################################################
# Sudachiの辞書をビルドする. ここは時間かかる
######################################################################
FROM maven:3-jdk-8 as sudachi-dic

# Heapを多めにとっておかないと、辞書をビルドするときOutOfMemoryに遭遇する
ENV MAVEN_OPTS=-Xmx4096m

ARG SUDACHI_VER

COPY --from=sudachi /Sudachi/target/sudachi-${SUDACHI_VER}-SNAPSHOT.jar /Sudachi/target/sudachi-${SUDACHI_VER}-SNAPSHOT.jar

RUN --mount=type=cache,target=/root/.m2 \
    curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
    apt-get install git-lfs && \
    git lfs install && \
    : "sudachiのjarファイルをmavenに登録する" && \
    mvn install:install-file \
    -Dfile=/Sudachi/target/sudachi-${SUDACHI_VER}-SNAPSHOT.jar \
    -DgroupId=com.worksap.nlp \
    -DartifactId=sudachi \
    -Dversion=${SUDACHI_VER}-SNAPSHOT \
    -Dpackaging=jar \
    -DgeneratePom=true && \
    : "辞書をCloneしてビルドする" && \
    git clone https://github.com/WorksApplications/SudachiDict.git && \
    cd SudachiDict && git pull origin develop && \
    sed -i -e "s/0.1.2-SNAPSHOT/${SUDACHI_VER}-SNAPSHOT/g" pom.xml && \
    sed -i -e 's#</dependencies>#<dependency><groupId>com.worksap.nlp</groupId><artifactId>jdartsclone</artifactId><version>1.0.1</version></dependency></dependencies>#g' pom.xml && \
    mvn package -Dmaven.test.skip=true -Dfile.encoding=UTF-8 && \
    mkdir -p /sudachi-dic && \
    mv ./target/*.dic /sudachi-dic/

######################################################################
# elsaticsearch-sudachiをビルドする
######################################################################
FROM maven:3-jdk-8 as sudachi-plugin

ARG ELASTIC_VER
ARG ELASTIC_SUDACHI_VER
ENV ELASTIC_SUDACHI_FILENAME=analysis-sudachi-elasticsearch${ELASTIC_SUDACHI_VER}-SNAPSHOT.zip
ENV ELASTIC_SUDACHI_URL=https://github.com/WorksApplications/elasticsearch-sudachi/releases/download/v${ELASTIC_SUDACHI_VER}/${ELASTIC_SUDACHI_FILENAME}

RUN --mount=type=cache,target=/root/.m2 \
    git clone https://github.com/WorksApplications/elasticsearch-sudachi.git && \
    cd elasticsearch-sudachi && \
    git checkout -b worktag refs/tags/v${ELASTIC_SUDACHI_VER} && \
     sed -i -e "s#<artifactId>analysis-sudachi-elasticsearch.*</artifactId>#<artifactId>analysis-sudachi-elasticsearch${ELASTIC_VER}</artifactId>#g" pom.xml && \
    mvn package -Dmaven.test.skip=true && \
    mv ./target/releases /sudachi-plugin/

######################################################################
# Sudachiプラグインを入れたElasticsearchのイメージをビルドする
######################################################################
FROM docker.elastic.co/elasticsearch/elasticsearch:${ELASTIC_VER}

COPY --chown=elasticsearch:root --from=sudachi-dic /sudachi-dic/*.dic ./config/sudachi/
COPY --chown=elasticsearch:root --from=sudachi-plugin /sudachi-plugin/*.zip /tmp/elasticsearch/plugins/

ARG ELASTIC_SUDACHI_VER
ARG ELASTIC_SUDACHI_FILENAME=analysis-sudachi-elasticsearch${ELASTIC_SUDACHI_VER}.zip

RUN  bin/elasticsearch-plugin install -v  file:///tmp/elasticsearch/plugins/${ELASTIC_SUDACHI_FILENAME}

注意点

DOCKER_BUILDKITを使ってます。

export DOCKER_BUILDKIT=1 でビルドします。

Dockerfileのポイント

Sudachi本体のビルド

######################################################################
# Sudachi本体のビルド. 辞書ビルドで、このjarが必要になる
######################################################################
FROM maven:3-jdk-8 as sudachi
RUN --mount=type=cache,target=/root/.m2 \
    git clone https://github.com/WorksApplications/Sudachi.git && \
    cd Sudachi && \
    mvn package -Dfile.encoding=UTF-8 

ここは何もないですね。git cloneしてmavenでビルドするだけです。

Sudachiの辞書のビルド

######################################################################
# Sudachiの辞書をビルドする. ここは時間かかる
######################################################################
FROM maven:3-jdk-8 as sudachi-dic

# Heapを多めにとっておかないと、辞書をビルドするときOutOfMemoryに遭遇する
ENV MAVEN_OPTS=-Xmx4096m

ARG SUDACHI_VER

COPY --from=sudachi /Sudachi/target/sudachi-${SUDACHI_VER}-SNAPSHOT.jar /Sudachi/target/sudachi-${SUDACHI_VER}-SNAPSHOT.jar

RUN --mount=type=cache,target=/root/.m2 \
    curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
    apt-get install git-lfs && \
    git lfs install && \
    : "sudachiのjarファイルをmavenに登録する" && \
    mvn install:install-file \
    -Dfile=/Sudachi/target/sudachi-${SUDACHI_VER}-SNAPSHOT.jar \
    -DgroupId=com.worksap.nlp \
    -DartifactId=sudachi \
    -Dversion=${SUDACHI_VER}-SNAPSHOT \
    -Dpackaging=jar \
    -DgeneratePom=true && \
    : "辞書をCloneしてビルドする" && \
    git clone https://github.com/WorksApplications/SudachiDict.git && \
    cd SudachiDict && git pull origin develop && \
    sed -i -e "s/0.1.2-SNAPSHOT/${SUDACHI_VER}-SNAPSHOT/g" pom.xml && \
    sed -i -e 's#</dependencies>#<dependency><groupId>com.worksap.nlp</groupId><artifactId>jdartsclone</artifactId><version>1.0.1</version></dependency></dependencies>#g' pom.xml && \
    mvn package -Dmaven.test.skip=true -Dfile.encoding=UTF-8 && \
    mkdir -p /sudachi-dic && \
    mv ./target/*.dic /sudachi-dic/

先ほどビルドしたsudachiのjarを使うことにしましょう。

Sudachiの辞書は、 https://github.com/WorksApplications/SudachiDict にありますが、今のところdevelopブランチしかないです。

sudachiのバージョン問題

2019/04/09時点では、このdevelopブランチのpomファイルでは、0.1.2-SNAPSHOTを使うとありますが、この時点でのSudachi本体の方は、0.2.1-SNAPSHOTまで上がっています。

仕方ないのでsedでpomを書き換えます。

sed -i -e "s/0.1.2-SNAPSHOT/${SUDACHI_VER}-SNAPSHOT/g" pom.xml 

jar足りない問題

f:id:tsgkdt:20190409230034p:plain

標準のpomのまま続けてビルドしようとすると、NoClassDefFoundErrorに見舞われます。 足りないのは、jdartscloneです。これをdependenciesに足してやりましょう。
またまた無理やりsedでpomをかきかえます。

 sed -i -e 's#</dependencies>#<dependency><groupId>com.worksap.nlp</groupId><artifactId>jdartsclone</artifactId><version>1.0.1</version></dependency></dependencies>#g' pom.xml 

メモリ足りない問題

f:id:tsgkdt:20190409230423p:plain
OOM

何も考えずにmvn packageを実行すると長い間またされた後に、OutOfMemoryで落ちるという悲劇が待っています。

多めにメモリを割り当てておきましょう。

# Heapを多めにとっておかないと、辞書をビルドするときOutOfMemoryに遭遇する
ENV MAVEN_OPTS=-Xmx4096m

elasticsearch-sudachiプラグインのビルド

######################################################################
# elsaticsearch-sudachiをビルドする
######################################################################
FROM maven:3-jdk-8 as sudachi-plugin

ARG ELASTIC_VER
ARG ELASTIC_SUDACHI_VER
ENV ELASTIC_SUDACHI_FILENAME=analysis-sudachi-elasticsearch${ELASTIC_SUDACHI_VER}-SNAPSHOT.zip
ENV ELASTIC_SUDACHI_URL=https://github.com/WorksApplications/elasticsearch-sudachi/releases/download/v${ELASTIC_SUDACHI_VER}/${ELASTIC_SUDACHI_FILENAME}

RUN --mount=type=cache,target=/root/.m2 \
    git clone https://github.com/WorksApplications/elasticsearch-sudachi.git && \
    cd elasticsearch-sudachi && \
    git checkout -b worktag refs/tags/v${ELASTIC_SUDACHI_VER} && \
     sed -i -e "s#<artifactId>analysis-sudachi-elasticsearch.*</artifactId>#<artifactId>analysis-sudachi-elasticsearch${ELASTIC_VER}</artifactId>#g" pom.xml && \
    mvn package -Dmaven.test.skip=true && \
    mv ./target/releases /sudachi-plugin/

https://github.com/WorksApplications/elasticsearch-sudachi

こちらの方は辞書とは異なり、リリースごとにタグが打たれています。 なので、ElasticsearchとSudachiのバージョンの組み合わせの環境が取得しやすいですね。

こんな感じで、指定バージョンのソースを取得しましょう。

 git checkout -b worktag refs/tags/v${ELASTIC_SUDACHI_VER} 

6.7.0なのに6.7.1になっていた件

v6.7.0-1.3.0をビルドしようとしていたところ、出力されたartifactを見るとv6.7.1-1.3.0になっていて困りました。

https://github.com/WorksApplications/elasticsearch-sudachi/blob/v6.7.0-1.3.0/pom.xml

  <artifactId>analysis-sudachi-elasticsearch6.7</artifactId>

6.7までしか指定していないと、そのときの最新版を取ってしまうようです。 なので6.7.0しか世の中に存在しないときは良いんですが、6.7.1が出たら6.7.0の環境のつもりなのに6.7.1になってしまいます。

そうならないようにするためには、6.7で止めるのではなく最後のバージョンまで指定してやればよいです。

そこで、sed

 sed -i -e "s#<artifactId>analysis-sudachi-elasticsearch.*</artifactId>#<artifactId>analysis-sudachi-elasticsearch${ELASTIC_VER}</artifactId>#g" pom.xml

Elasticsearchへ

######################################################################
# Sudachiプラグインを入れたElasticsearchのイメージをビルドする
######################################################################
FROM docker.elastic.co/elasticsearch/elasticsearch:${ELASTIC_VER}

COPY --chown=elasticsearch:root --from=sudachi-dic /sudachi-dic/*.dic ./config/sudachi/
COPY --chown=elasticsearch:root --from=sudachi-plugin /sudachi-plugin/*.zip /tmp/elasticsearch/plugins/

ARG ELASTIC_SUDACHI_VER
ARG ELASTIC_SUDACHI_FILENAME=analysis-sudachi-elasticsearch${ELASTIC_SUDACHI_VER}.zip

RUN  bin/elasticsearch-plugin install -v  file:///tmp/elasticsearch/plugins/${ELASTIC_SUDACHI_FILENAME}

事前のステージでビルドした成果物をもってきて、辞書をコピー、プラグインのインストールの2ステップをやって終わりです。 お疲れさまでした。