ElasticsearchでKuromoji Tokenizerを試す
ElasticsearchでKuromoji Tokenizerを試してみたメモです。
前回、NGram TokenizerでN-Gramを試してみたので、
今回は形態素解析であるKuromoji Tokenizerを試してみました。
Ubuntu上でElasticsearch5.4.0で試してみます。
インストール・起動
kuromoji tokenizerはデフォルトでは入っていないのでインストールする必要があります。
Japanese (kuromoji) Analysis pluginをインストールします。
Japanese (kuromoji) Analysis pluginには下記のトークナイザとフィルタが入っており、
kuromoji tokenizerが含まれています。
- kuromoji_tokenizer
- kuromoji_baseform token filter
- kuromoji_part_of_speech token filter
- cjk_width token filter
- ja_stop token filter
- kuromoji_stemmer token filter
- lowercase token filter
elasticsearch-pluginを利用してインストールします。
$ sudo bin/elasticsearch-plugin install analysis-kuromoji -> Downloading analysis-kuromoji from elastic [=================================================] 100% -> Installed analysis-kuromoji
インストール後は再起動する必要があります。
$ ./elasticsearch
プラグインがインストールされたか、_nodes/pluginsのエンドポイントを指定して、確認してみます。
pluginsにanalysis-kuromojiが含まれているのが分かります。
$ curl -X GET 'http://localhost:9200/_nodes/plugins?pretty' { "_nodes" : { "total" : 1, "successful" : 1, "failed" : 0 }, "cluster_name" : "elasticsearch", "nodes" : { "7xgQmDgJS1mPi02p2LzUrg" : { "name" : "7xgQmDg", "transport_address" : "10.0.2.15:9300", "host" : "10.0.2.15", "ip" : "10.0.2.15", "version" : "5.4.0", "build_hash" : "780f8c4", "roles" : [ "master", "data", "ingest" ], "plugins" : [ { "name" : "analysis-kuromoji", "version" : "5.4.0", "description" : "The Japanese (kuromoji) Analysis plugin integrates Lucene kuromoji analysis module into elasticsearch.", "classname" : "org.elasticsearch.plugin.analysis.kuromoji.AnalysisKuromojiPlugin", "has_native_controller" : false } ], "modules" : [ { "name" : "aggs-matrix-stats", "version" : "5.4.0", "description" : "Adds aggregations whose input are a list of numeric fields and output includes a matrix.", "classname" : "org.elasticsearch.search.aggregations.matrix.MatrixAggregationPlugin", "has_native_controller" : false }, : : : :
アナライザ設定
アナライザを設定するためのjsonファイルを用意します。
analyzerの項目にはmy_kuromoji_analyzerという名前を設定し、
typeにcustomを設定し、tokenizerにはkuromoji_tokenizerを指定します。
kuromoji_analysis.json
{ "settings": { "analysis": { "analyzer": { "my_kuromoji_analyzer": { "type": "custom", "tokenizer": "kuromoji_tokenizer" } } } } }
kuromoji_analysis.jsonを指定してmy_indexというインデックスを作成。
$ curl -X PUT 'localhost:9200/my_index' -d @kuromoji_analysis.json
インデックスを確認してみると、analyzerのtokenizerの項目に
kuromoji_tokenizerが設定されていることが分かります。
$ curl -X GET 'localhost:9200/my_index/?pretty' { "my_index" : { "aliases" : { }, "mappings" : { }, "settings" : { "index" : { "number_of_shards" : "5", "provided_name" : "my_index", "creation_date" : "1495799529581", "analysis" : { "analyzer" : { "my_kuromoji_analyzer" : { "type" : "custom", "tokenizer" : "kuromoji_tokenizer" } } }, "number_of_replicas" : "1", "uuid" : "fFuf3TV7SZSseri8U_t6nQ", "version" : { "created" : "5040099" } } } } }
確認
アナライザを確認するには/_analyzeでanalyze APIのエンドポイントを指定します。
analyzerでmy_kuromoji_analyzerを指定し、textにアナライズ対象の文章を指定します。
実行してみると、日本語の単語ごとに分割されていることが分かります。
$ curl -X POST 'localhost:9200/my_index/_analyze?pretty' -d '{"analyzer": "my_kuromoji_analyzer", "text": "吾輩は猫である。"}' { "tokens" : [ { "token" : "吾輩", "start_offset" : 0, "end_offset" : 2, "type" : "word", "position" : 0 }, { "token" : "は", "start_offset" : 2, "end_offset" : 3, "type" : "word", "position" : 1 }, { "token" : "猫", "start_offset" : 3, "end_offset" : 4, "type" : "word", "position" : 2 }, { "token" : "で", "start_offset" : 4, "end_offset" : 5, "type" : "word", "position" : 3 }, { "token" : "ある", "start_offset" : 5, "end_offset" : 7, "type" : "word", "position" : 4 } ] }
mapping定義
マッピングでフィールドごとにアナライザを設定できます。
titleとsentenceというフィールドを持つnatsumeタイプを定義します。
titleとsentenceフィールドにはそれぞれanalyzerにmy_kuromoji_analyzerを指定します。
mapping.json
{ "settings": { "analysis": { "analyzer": { "my_kuromoji_analyzer": { "type": "custom", "tokenizer": "kuromoji_tokenizer" } } } }, "mappings": { "natsume": { "properties": { "title": { "type": "string", "index": "analyzed", "analyzer": "my_kuromoji_analyzer" }, "sentence": { "type": "string", "index": "analyzed", "analyzer": "my_kuromoji_analyzer" } } } } }
先ほど作成したインデックスを削除
curl -X DELETE 'localhost:9200/my_index'
mapping.jsonを指定してmy_indexを再作成。
$ curl -X PUT 'localhost:9200/my_index/' -d @mapping.json
インデックスを確認してみるとtitleとsentenceフィールドにmy_kuromoji_analyzerが設定されてるのが分かります。
$ curl -X GET 'localhost:9200/my_index/?pretty' { "my_index" : { "aliases" : { }, "mappings" : { "natsume" : { "properties" : { "sentence" : { "type" : "text", "analyzer" : "my_kuromoji_analyzer" }, "title" : { "type" : "text", "analyzer" : "my_kuromoji_analyzer" } } } }, "settings" : { "index" : { "number_of_shards" : "5", "provided_name" : "my_index", "creation_date" : "1495800487967", "analysis" : { "analyzer" : { "my_kuromoji_analyzer" : { "type" : "custom", "tokenizer" : "kuromoji_tokenizer" } } }, "number_of_replicas" : "1", "uuid" : "7LAnD9sqTPa1ttdI-vK_YQ", "version" : { "created" : "5040099" } } } } }
確認
確認用のドキュメントを登録。
curl -X PUT 'localhost:9200/my_index/natsume/1?pretty' -d ' { "title": "坊っちゃん", "sentence": "親譲りの無鉄砲で小供の時から損ばかりしている。" }'
curl -X PUT 'localhost:9200/my_index/natsume/2?pretty' -d ' { "title": "吾輩は猫である", "sentence": "吾輩は猫である。名前はまだ無い。" }'
matchクエリでsentenceフィールドを指定して検索してみます。
"吾輩"で検索。
$ curl -X GET 'http://localhost:9200/my_index/_search?pretty' -d '{"query":{"match":{"sentence":"吾輩"}}}'
kuromojiで分割されている単語なのでヒットしました。
{ "took" : 37, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 0.27233246, "hits" : [ { "_index" : "my_index", "_type" : "natsume", "_id" : "2", "_score" : 0.27233246, "_source" : { "title" : "吾輩は猫である", "sentence" : "吾輩は猫である。名前はまだ無い。" } } ] } }
"吾輩は"で検索。
$ curl -X GET 'http://localhost:9200/my_index/_search?pretty' -d '{"query":{"match":{"sentence":"吾輩が"}}}'
分割された"吾輩"で単語がヒットします。
{ "took" : 11, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 0.27233246, "hits" : [ { "_index" : "my_index", "_type" : "natsume", "_id" : "2", "_score" : 0.27233246, "_source" : { "title" : "吾輩は猫である", "sentence" : "吾輩は猫である。名前はまだ無い。" } } ] } }
"吾"で検索。
>|json| $ curl -X GET 'http://localhost:9200/my_index/_search?pretty' -d '{"query":{"match":{"sentence":"吾"}}}'
分割された単語には含まれないのでヒットしません。
{ "took" : 3, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 0, "max_score" : null, "hits" : [ ] } }
"子猫"で検索。
$ curl -X GET 'http://localhost:9200/my_index/_search?pretty' -d '{"query":{"match":{"sentence":"子猫"}}}'
"子猫"はkuromojiで"子"と"猫"に分割されないので、ヒットしません。
{ "took" : 3, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 0, "max_score" : null, "hits" : [ ] } }
終わり