├── .gitignore ├── elasticsearch ├── sudachi │ ├── custom_dict.txt │ ├── README.md │ └── sudachi.json └── Dockerfile ├── Makefile ├── docker-compose.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /elasticsearch/sudachi/custom_dict.txt: -------------------------------------------------------------------------------- 1 | po3rin,4786,4786,5000,po3rin,名詞,固有名詞,一般,*,*,*,po3rin,po3rin,*,*,*,*,* -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: ## start container 3 | docker-compose up -d 4 | 5 | .PHONY: down 6 | down: ## down container 7 | docker-compose down 8 | 9 | .PHONY: build 10 | build: ## build container 11 | docker-compose build 12 | 13 | ## help target ------------------------- 14 | 15 | .PHONY: help 16 | help: ## display this help screen 17 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' 18 | 19 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | elasticsearch: 4 | build: ./elasticsearch 5 | container_name: elasticsearch 6 | environment: 7 | - "ES_JAVA_OPTS=-Xms512m -Xmx512m" 8 | - node.name=es01 9 | - discovery.type=single-node 10 | ports: 11 | - '9200:9200' 12 | - '9300:9300' 13 | 14 | kibana: 15 | image: docker.elastic.co/kibana/kibana:7.4.0 16 | links: 17 | - elasticsearch 18 | environment: 19 | - ELASTICSEARCH_URL=http://elasticsearch:9200 20 | ports: 21 | - 5601:5601 22 | -------------------------------------------------------------------------------- /elasticsearch/sudachi/README.md: -------------------------------------------------------------------------------- 1 | # Sudachi Plugin 2 | 3 | 形態素解析器 Sudachi の Elasticsearch Plugin 用のディレクトリです。 4 | 5 | ## 設定 6 | 7 | ```sudachi.json``` で設定を変更できる。sudachi辞書のタイプを変更する場合は Dockerfile の ARG も変更する必要がある。 8 | 9 | ## ビルド 10 | 11 | 手元でビルドする場合は下記のコマンドで実行できる。```pom.xml``` を Elastisearch のバージョンに合わせて修正する必要あり。 12 | 13 | ``` 14 | git clone https://github.com/WorksApplications/elasticsearch-sudachi.git 15 | $ cd elasticsearch-sudachi 16 | $ docker run -it --rm --name my-sudachi-project -v (pwd):/usr/src/mymaven -w /usr/src/mymaven maven:3.3-jdk-8 mvn package 17 | ``` 18 | 19 | ## Reference 20 | https://qiita.com/sorami/items/99604ef105f13d2d472b 21 | 22 | 23 | ## 辞書 24 | 25 | 辞書はここで手に入る 26 | https://github.com/WorksApplications/SudachiDict 27 | 28 | 辞書を変更する場合は```sudachi.json```の```systemDict```フィールドと、```docker/Dockerfile```の```sudachi_dict_type```を変更する必要があります。 29 | -------------------------------------------------------------------------------- /elasticsearch/sudachi/sudachi.json: -------------------------------------------------------------------------------- 1 | { 2 | "systemDict": "system_small.dic", 3 | "userDict": [ 4 | "custom.dic" 5 | ], 6 | "inputTextPlugin": [ 7 | { 8 | "class": "com.worksap.nlp.sudachi.DefaultInputTextPlugin" 9 | }, 10 | { 11 | "class": "com.worksap.nlp.sudachi.ProlongedSoundMarkInputTextPlugin", 12 | "prolongedSoundMarks": [ 13 | "ー", 14 | "-", 15 | "⁓", 16 | "〜", 17 | "〰" 18 | ], 19 | "replacementSymbol": "ー" 20 | } 21 | ], 22 | "oovProviderPlugin": [ 23 | { 24 | "class": "com.worksap.nlp.sudachi.MeCabOovProviderPlugin" 25 | }, 26 | { 27 | "class": "com.worksap.nlp.sudachi.SimpleOovProviderPlugin", 28 | "oovPOS": [ 29 | "補助記号", 30 | "一般", 31 | "*", 32 | "*", 33 | "*", 34 | "*" 35 | ], 36 | "leftId": 5968, 37 | "rightId": 5968, 38 | "cost": 3857 39 | } 40 | ], 41 | "pathRewritePlugin": [ 42 | { 43 | "class": "com.worksap.nlp.sudachi.JoinNumericPlugin", 44 | "joinKanjiNumeric": true 45 | }, 46 | { 47 | "class": "com.worksap.nlp.sudachi.JoinKatakanaOovPlugin", 48 | "oovPOS": [ 49 | "名詞", 50 | "普通名詞", 51 | "一般", 52 | "*", 53 | "*", 54 | "*" 55 | ], 56 | "minLength": 3 57 | } 58 | ] 59 | } -------------------------------------------------------------------------------- /elasticsearch/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ibmjava:8-jre-alpine as dict_builder 2 | 3 | ## 辞書の種類の指定(small/core/full) 4 | ARG sudachi_dict_type="small" 5 | 6 | ## ユーザー辞書ソースを持ってくる 7 | COPY sudachi/custom_dict.txt /home 8 | 9 | WORKDIR /home 10 | 11 | # Sudachiプラグインのjavaファイルを持ってくる (バイナリ辞書の作成のため) 12 | RUN wget https://github.com/WorksApplications/elasticsearch-sudachi/releases/download/v7.4.0-1.3.1/analysis-sudachi-elasticsearch7.4-1.3.1.zip && \ 13 | unzip analysis-sudachi-elasticsearch7.4-1.3.1.zip && \ 14 | # 用意されているシステム辞書を持ってくる 15 | wget https://object-storage.tyo2.conoha.io/v1/nc_2520839e1f9641b08211a5c85243124a/sudachi/sudachi-dictionary-20190718-${sudachi_dict_type}.zip && \ 16 | unzip sudachi-dictionary-20190718-${sudachi_dict_type}.zip && \ 17 | # バイナリ辞書の作成 18 | java -Dfile.encoding=UTF-8 -cp /home/sudachi-0.3.0.jar com.worksap.nlp.sudachi.dictionary.UserDictionaryBuilder -o /home/custom.dic -s /home/sudachi-dictionary-20190718/system_${sudachi_dict_type}.dic /home/custom_dict.txt 19 | 20 | # ========= custom dict builder ========== 21 | 22 | FROM elasticsearch:7.4.0 23 | 24 | ARG sudachi_dict_type="small" 25 | 26 | # Sudachiプラグインの設定ファイル 27 | COPY sudachi/sudachi.json /usr/share/elasticsearch/config/sudachi/ 28 | # 前ステージでダウンロードしたSudachiのシステム辞書 29 | COPY --from=dict_builder /home/sudachi-dictionary-20190718/system_${sudachi_dict_type}.dic /usr/share/elasticsearch/config/sudachi/ 30 | # 前ステージで作ったユーザー辞書 31 | COPY --from=dict_builder /home/custom.dic /usr/share/elasticsearch/config/sudachi/ 32 | # 前ステージでダウンロードしたプラグイン 33 | COPY --from=dict_builder /home/analysis-sudachi-elasticsearch7.4-1.3.1.zip /usr/share/elasticsearch/ 34 | 35 | # Sudachiプラグインインストール 36 | RUN elasticsearch-plugin install file:///usr/share/elasticsearch/analysis-sudachi-elasticsearch7.4-1.3.1.zip && \ 37 | rm /usr/share/elasticsearch/analysis-sudachi-elasticsearch7.4-1.3.1.zip 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elasticsearch + Sudachi + Docker でユーザー辞書登録ハンズオン 2 | 3 | 今回は Elasticsearch + Sudachi でユーザー辞書を使う Dockerfile を作ったので作り方を共有します。 4 | 5 | ## 今回のハンズオンの最終構成 6 | 7 | 最終的に下記のような構成を目指します。 8 | 9 | ```bash 10 | . 11 | ├── docker-compose.yml 12 | └── elasticsearch 13 | ├── Dockerfile 14 | └── sudachi 15 | ├── README.md 16 | ├── custom_dict.txt 17 | └── sudachi.json 18 | ``` 19 | 20 | ## custom_dict.txt 21 | 22 | まずはユーザー辞書の元となるユーザー辞書ソースファイルを作りましょう。ちなみにファイル名は任意の名前でもOKです。今回の例では僕のTwitterIDの「po3rin」を辞書に追加する例を見てみます。 23 | 24 | ```txt 25 | po3rin,4786,4786,5000,po3rin,名詞,固有名詞,一般,*,*,*,po3rin,po3rin,*,*,*,*,* 26 | ``` 27 | 28 | フォーマットに関してはドキュメントに全てまとまっているのでこちらを参照して下さい。 29 | https://github.com/WorksApplications/Sudachi/blob/develop/docs/user_dict.md 30 | 31 | もちろん、こんなwordは辞書にないので本来は下記のようにバラバラにtokenizeされてしまいます。 32 | 33 | ```json 34 | { 35 | "tokens" : [ 36 | { 37 | "token" : "po", 38 | // ... 39 | } 40 | { 41 | "token" : "3", 42 | // ... 43 | } 44 | { 45 | "token" : "rin", 46 | // ... 47 | } 48 | ] 49 | } 50 | 51 | ``` 52 | 53 | この結果が最後にどうなるか後ほどみてきましょう。 54 | 55 | ## sudachi.json 56 | 57 | 続いて Sudachi プラグインの設定ファイルである sudachi.json を上書きできるようにファイルを準備しましょう。 58 | 59 | ```json 60 | { 61 | "systemDict": "system_small.dic", 62 | "userDict": [ 63 | "custom.dic" 64 | ], 65 | "inputTextPlugin": [ 66 | { 67 | "class": "com.worksap.nlp.sudachi.DefaultInputTextPlugin" 68 | }, 69 | { 70 | "class": "com.worksap.nlp.sudachi.ProlongedSoundMarkInputTextPlugin", 71 | "prolongedSoundMarks": [ 72 | "ー", 73 | "-", 74 | "⁓", 75 | "〜", 76 | "〰" 77 | ], 78 | "replacementSymbol": "ー" 79 | } 80 | ], 81 | "oovProviderPlugin": [ 82 | { 83 | "class": "com.worksap.nlp.sudachi.MeCabOovProviderPlugin" 84 | }, 85 | { 86 | "class": "com.worksap.nlp.sudachi.SimpleOovProviderPlugin", 87 | "oovPOS": [ 88 | "補助記号", 89 | "一般", 90 | "*", 91 | "*", 92 | "*", 93 | "*" 94 | ], 95 | "leftId": 5968, 96 | "rightId": 5968, 97 | "cost": 3857 98 | } 99 | ], 100 | "pathRewritePlugin": [ 101 | { 102 | "class": "com.worksap.nlp.sudachi.JoinNumericPlugin", 103 | "joinKanjiNumeric": true 104 | }, 105 | { 106 | "class": "com.worksap.nlp.sudachi.JoinKatakanaOovPlugin", 107 | "oovPOS": [ 108 | "名詞", 109 | "普通名詞", 110 | "一般", 111 | "*", 112 | "*", 113 | "*" 114 | ], 115 | "minLength": 3 116 | } 117 | ] 118 | } 119 | ``` 120 | 121 | ```systemDict``` には使うシステム辞書、```userDict``` にはこれからビルドするバイナリ辞書ファイルを指定します。ちなみに ```userDict``` には複数指定可能です。 122 | 123 | 124 | ## Dockerfile 125 | 126 | それではユーザー辞書ソースファイルをビルドして一気にElasticsearchを立ち上げるDockerfileを作りましょう。 127 | ```elasticsearch```ディレクトリの中にDockerfileを準備します。中身は下記です。 128 | 129 | ```Dockerfile 130 | FROM ibmjava:8-jre-alpine as dict_builder 131 | 132 | ## 辞書の種類の指定(small/core/full) 133 | ARG sudachi_dict_type="small" 134 | 135 | ## ユーザー辞書ソースを持ってくる 136 | COPY sudachi/custom_dict.txt /home 137 | 138 | WORKDIR /home 139 | 140 | https://github.com/WorksApplications/elasticsearch-sudachi/releases/download/v7.4.0-1.3.1/analysis-sudachi-elasticsearch7.4-1.3.1.zip 141 | 142 | # Sudachiプラグインのjavaファイルを持ってくる (バイナリ辞書の作成のため) 143 | RUN wget https://github.com/WorksApplications/elasticsearch-sudachi/releases/download/v7.4.0-1.3.1/analysis-sudachi-elasticsearch7.4-1.3.1.zip && \ 144 | unzip analysis-sudachi-elasticsearch7.4-1.3.1.zip && \ 145 | # 用意されているシステム辞書を持ってくる 146 | wget https://object-storage.tyo2.conoha.io/v1/nc_2520839e1f9641b08211a5c85243124a/sudachi/sudachi-dictionary-20190718-${sudachi_dict_type}.zip && \ 147 | unzip sudachi-dictionary-20190718-${sudachi_dict_type}.zip && \ 148 | # バイナリ辞書の作成 149 | java -Dfile.encoding=UTF-8 -cp /home/sudachi-0.3.0.jar com.worksap.nlp.sudachi.dictionary.UserDictionaryBuilder -o /home/custom.dic -s /home/sudachi-dictionary-20190718/system_small.dic /home/custom_dict.txt 150 | 151 | 152 | FROM elasticsearch:7.4.0 153 | 154 | ARG sudachi_dict_type="small" 155 | 156 | # Sudachiプラグインの設定ファイル 157 | COPY sudachi/sudachi.json /usr/share/elasticsearch/config/sudachi/ 158 | # 前ステージでダウンロードしたSudachiのシステム辞書 159 | COPY --from=dict_builder /home/sudachi-dictionary-20190718/system_${sudachi_dict_type}.dic /usr/share/elasticsearch/config/sudachi/ 160 | # 前ステージで作ったユーザー辞書 161 | COPY --from=dict_builder /home/custom.dic /usr/share/elasticsearch/config/sudachi/ 162 | # 前ステージでダウンロードしたプラグイン 163 | COPY --from=dict_builder /home/analysis-sudachi-elasticsearch7.4-1.3.1.zip /usr/share/elasticsearch/ 164 | 165 | # Sudachiプラグインインストール 166 | RUN elasticsearch-plugin install file:///usr/share/elasticsearch/analysis-sudachi-elasticsearch7.4-1.3.1.zip && \ 167 | rm /usr/share/elasticsearch/analysis-sudachi-elasticsearch7.4-1.3.1.zip 168 | 169 | ``` 170 | 171 | SudachiプラグインのバージョンはElasticsearchのバージョンと基本的に一致させてください。マルチステージビルドにしている理由は余計なJavaコマンドなど不要な物をElasticserchのイメージに含めたくないからです。 ```dict_builder``` ステージでは主にユーザー辞書ソースからバイナリ辞書ファイルのビルドを行なっています。[ドキュメント](https://github.com/WorksApplications/Sudachi/blob/develop/docs/user_dict.md)にも記載がありますが、下記のようなコマンドでユーザー辞書ソースからバイナリ辞書を作成できます。 172 | 173 | 174 | ```bash 175 | $ java -Dfile.encoding=UTF-8 -cp sudachi-XX.jar com.worksap.nlp.sudachi.dictionary.UserDictionaryBuilder -o output.dic -s system_core.dic [-d comment] input 176 | ``` 177 | 178 | output.dic 出力するバイナリ辞書ファイル名 179 | system_core.dic Sudachi のシステム辞書 180 | comment バイナリ辞書のヘッダーに埋め込むコメント 181 | input.csv ユーザ辞書ソースファイル名 182 | 183 | もちろん手元でビルドした物をDockerfileにコピーしてきても良いですが、筆者は管理するファイルを減らしたい&重い辞書バイナリをGitで管理したくない&Java環境の構築がめんどいという理由でDocker内で完結させています。 184 | 185 | ## 動作確認 186 | 187 | 動作確認用の docker-compose.yml を作ります。Kibanaを入れているのはKibanaに搭載されている```DevTools```という機能が便利だからです。 188 | 189 | ```yml 190 | version: '3.6' 191 | services: 192 | elasticsearch: 193 | build: ./elasticsearch 194 | container_name: elasticsearch 195 | environment: 196 | - "ES_JAVA_OPTS=-Xms512m -Xmx512m" 197 | - discovery.type=single-node 198 | - node.name=es01 199 | ports: 200 | - '9200:9200' 201 | - '9300:9300' 202 | 203 | kibana: 204 | image: docker.elastic.co/kibana/kibana:7.4.0 205 | links: 206 | - elasticsearch 207 | environment: 208 | - ELASTICSEARCH_URL=http://elasticsearch:9200 209 | ports: 210 | - 5601:5601 211 | 212 | ``` 213 | 214 | 早速立ち上げます。ビルドと立ち上げは下記コマンド一発です。 215 | 216 | ```bash 217 | $ docker-compose up --build 218 | ``` 219 | 220 | 早速 Kibana の URL (http://localhost:5601) にブラウザからアクセスしてみましょう。Menu に ```DevTools```があるので開いてConsoleに以下を記述します。 221 | 222 | ```json 223 | PUT /sample-index 224 | { 225 | "settings": { 226 | "number_of_shards": 1, 227 | "analysis": { 228 | "analyzer": { 229 | "sudachi_analyzer": { 230 | "type": "custom", 231 | "tokenizer": "sudachi_tokenizer" 232 | } 233 | }, 234 | "tokenizer": { 235 | "sudachi_tokenizer": { 236 | "type": "sudachi_tokenizer", 237 | "mode": "search", 238 | "discard_punctuation": true, 239 | "resources_path": "/usr/share/elasticsearch/config/sudachi/", 240 | "settings_path": "/usr/share/elasticsearch/config/sudachi/sudachi.json" 241 | } 242 | } 243 | } 244 | }, 245 | "mappings": { 246 | "properties": { 247 | "text": { 248 | "type": "text", 249 | "analyzer": "sudachi_analyzer" 250 | } 251 | } 252 | } 253 | } 254 | 255 | POST sample-index/_analyze 256 | { 257 | "analyzer": "sudachi_analyzer", 258 | "text": "po3rin" 259 | } 260 | ``` 261 | 262 | ```settings_path``` で指定している ```sudachi.json``` を見て使う辞書をtokenizerが理解してくれます。 263 | DevToolsだけでElasticsearchに対してAPIが叩けます。これらを実行すると下記のレスポンスが確認できます。 264 | 265 | ```json 266 | { 267 | "tokens" : [ 268 | { 269 | "token" : "po3rin", 270 | "start_offset" : 0, 271 | "end_offset" : 6, 272 | "type" : "word", 273 | "position" : 0 274 | } 275 | ] 276 | } 277 | ``` 278 | 279 | ユーザー辞書に登録した「po3rin」が一単語として認識できています。 280 | 281 | 以上です。 282 | --------------------------------------------------------------------------------