話題の記事

Kuromojiで日本語全文検索 – AWSで始めるElasticSearch(1)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

初めまして、ブロガーとして出張してきました@smokeymonkeyです。

今回、AWS上にElasticSearchを導入し、試行錯誤した結果をまとめてみました。シリーズものとして何度か続けていきたいと思いますので、どうぞ宜しくお願い致します。

ElasticSearchとは

Apache v2ライセンスで公開されているオープンソースソフトウェアであり、全文検索エンジンであるLuceneを使用した、全文検索システムです。特徴として

  • RESTfulなAPIが使える
  • InputもOutputもJSON
  • スキーマフリーなので面倒な定義無しにデータを登録可能

等があります。

Kuromojiとは

Kuromojiはatilika社製のJavaで書かれた日本語形態素解析ソフトウェアで、Apache v2ライセンスで公開されているオープンソースソフトウェアです。形態素解析としてはChaSenMeCabがメジャーで古くから使われていますが、Kuromojiは比較的新しいソフトウェアです。

Amazon LinuxへのElasticSearchのセットアップ

ElasticSearchの動作にはJavaが必要ですが、Amazon Linuxの場合初期導入されています。

$ java -version
java version "1.6.0_24"<br />OpenJDK Runtime Environment (IcedTea6 1.11.13) (amazon-65.1.11.13.56.amzn1-x86_64)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

ElasticSearchの公式サイトから最新バージョンをダウンロードします。ElasticSearchはzipファイル、tar.gzファイル、debパッケージファイル、rpmパッケージファイルにて配布されています。今回はrpmパッケージからインストールを行います。

$ wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-0.90.5.noarch.rpm
$ sudo rpm -ivh ./elasticsearch-0.90.5.noarch.rpm
Preparing...                          ################################# [100%]
Updating / installing...
   1:elasticsearch-0.90.5-1           ################################# [100%]
Starting elasticsearch: [  OK  ]

ElasticSearchの動作確認

それでは簡単な動作確認をしてみます。まずはPUTを使ってテストデータを登録します。
ここではIndexを「mytest」、Typeを「test」としました。

$ curl -XPUT http://localhost:9200/mytest/test/1 -d '
> {
>   "title" : "memo",
>   "text"  : "hogehoge"
> }'
{"ok":true,"_index":"mytest","_type":"test","_id":"1","_version":1}

そしてGETを使って検索してみます。

$ curl -XGET http://localhost:9200/mytest/test/_search -d '
> {
>   "query":
>   { "match":{"title":"memo"}}
> }'
{
    "array": {
        "took": 85,
        "timed_out": false,
        "_shards": {
            "total": 5,
            "successful": 5,
            "failed": 0
        },
        "hits": {
            "total": 1,
            "max_score": 0.30685282,
            "hits": [
                {
                    "_index": "mytest",
                    "_type": "test",
                    "_id": "1",
                    "_score": 0.30685282,
                    "_source": {
                        "title": "memo",
                        "text": "hogehoge"
                    }
                }
            ]
        }
    }
}

titleが「memo」であるデータが戻り値として返ってきました!

Kuromojiプラグインのセットアップ

ElasticSearchのpluginコマンドを使って、Kuromojiプラグインをインストールします。

$ sudo /usr/share/elasticsearch/bin/plugin  --install elasticsearch/elasticsearch-analysis-kuromoji/1.5.0
-> Installing elasticsearch/elasticsearch-analysis-kuromoji/1.5.0...
Trying http://download.elasticsearch.org/elasticsearch/elasticsearch-analysis-kuromoji/elasticsearch-analysis-kuromoji-1.5.0.zip...
Downloading ....................................................DONE
Installed elasticsearch/elasticsearch-analysis-kuromoji/1.5.0 into /usr/share/elasticsearch/plugins/analysis-kuromoji

プラグインをインストールした後はElasticSearchの再起動が必要です。

$ sudo service elasticsearch restart
Stopping elasticsearch:                                    [  OK  ]
Starting elasticsearch:                                    [  OK  ]

Kuromojiプラグインの動作確認

それでは簡単な動作確認をしてみましょう。
kurotestというIndexで、kuromojiをアナライザと使うように設定します。

$ curl -XPUT 'http://localhost:9200/kurotest/' -d'
>  {
>      "index":{
>          "analysis":{
>              "tokenizer" : {
>                  "kuromoji" : {
>                     "type" : "kuromoji_tokenizer"
>                  }
>              },
>              "analyzer" : {
>                  "analyzer" : {
>                      "type" : "custom",
>                      "tokenizer" : "kuromoji"
>                  }
>              }
>          }
>      }
>  }'
{"ok":true,"acknowledged":true}

このkurotestにPOSTで日本語文字列を投げると、分かち書きされて返ってきます!

$ curl -XPOST 'http://localhost:9200/kurotest/_analyze?analyzer=analyzer&petty' -d '梅酒は水'
{
    "array": {
        "tokens": [
            {
                "token": "梅酒",
                "start_offset": 0,
                "end_offset": 2,
                "type": "word",
                "position": 1
            },
            {
                "token": "は",
                "start_offset": 2,
                "end_offset": 3,
                "type": "word",
                "position": 2
            },
            {
                "token": "水",
                "start_offset": 3,
                "end_offset": 4,
                "type": "word",
                "position": 3
            }
        ]
    }
}

ElasticSearchとKuromojiプラグインで日本語全文検索

お待たせしました!ここからが本番です。
まずはElasticSearchの設定ファイルを修正し、kuromojiをデフォルトアナライザとして設定します。設定後はElasticSearchの再起動が必要です。

$ sudo vi /etc/elasticsearch/elasticsearch.yml
index.analysis.analyzer.default.type: custom
index.analysis.analyzer.default.tokenizer: kuromoji_tokenizer
$ sudo service elasticsearch restart

それでは二つの日本語文字列をテストデータとして登録してみます。

$ curl -XPUT http://localhost:9200/jptest/test/1 -d '
>   {
>     "title" : "メモ",
>     "text"  : "梅酒は水"
>   }'
{"ok":true,"_index":"jptest","_type":"test","_id":"1","_version":1}

$ curl -XPUT http://localhost:9200/jptest/test/2 -d '
>   {
>     "title" : "メモ2",
>     "text"  : "麦酒は命"
>   }'
{"ok":true,"_index":"jptest","_type":"test","_id":"2","_version":1}

まずは「梅酒」という文字列で検索してみます。

$ curl -XGET http://localhost:9200/jptest/test/_search -d '
>    {
>      "query":
>      { "match":{"text":"梅酒"}}
>    }'
{
    "array": {
        "took": 3,
        "timed_out": false,
        "_shards": {
            "total": 5,
            "successful": 5,
            "failed": 0
        },
        "hits": {
            "total": 1,
            "max_score": 0.15342641,
            "hits": [
                {
                    "_index": "jptest",
                    "_type": "test",
                    "_id": "1",
                    "_score": 0.15342641,
                    "_source": {
                        "title": "メモ",
                        "text": "梅酒は水"
                    }
                }
            ]
        }
    }
}

ちゃんと「梅酒は水」がヒットしました!

次に「梅酒」という文字列で検索してみます。

$ curl -XGET http://localhost:9200/jptest/test/_search -d '
>     {
>        "query":>        { "match":{"text":"梅酒は"}}
>      }'
{
    "array": {
        "took": 5,
        "timed_out": false,
        "_shards": {
            "total": 5,
            "successful": 5,
            "failed": 0
        },
        "hits": {
            "total": 2,
            "max_score": 0.2169777,
            "hits": [
                {
                    "_index": "jptest",
                    "_type": "test",
                    "_id": "1",
                    "_score": 0.2169777,
                    "_source": {
                        "title": "メモ",
                        "text": "梅酒は水"
                    }
                },
                {
                    "_index": "jptest",
                    "_type": "test",
                    "_id": "2",
                    "_score": 0.02250402,
                    "_source": {
                        "title": "メモ2",
                        "text": "麦酒は命"
                    }
                }
            ]
        }
    }
}

「梅酒は水」と「麦酒は命」の2つがヒットしました。ここで注目したいのは"_score"です。
「梅酒は水」は「梅酒は」のうち3文字がヒットするためスコアが高く(0.2169777)、「麦酒は命」は「酒は」の2文字のみがヒットするためスコアが低く(0.02250402)なっています。これで分かち書きによって日本語全文検索が行われていることがわかります。

まとめ

ElasticSearchはIn/OutがJSONであることからとても汎用性の高いツールだと思います。次回は可用性を高めるべくClusterの設定を行いたいと思います。