(注 この記事は古くなったので、新しい記事をこちらに記載しています)
http://dotnsf.blog.jp/archives/1059206837.html


全文検索エンジン ElasticSearch に日本語形態素解析ソフトウェアである Kuromoji のプラグインを導入して、日本語全文検索環境を構築します。


まずは ElasticSearch をインストールします。ElasticSearch のインストールそのものの手順については以前のエントリを参照してください:
ElasticSearch を導入して CouchBase サーバーの全文検索を行う


ElasticSearch の導入ができたら、この段階で動作確認をしておきます。まずはデータを登録します(青字は実行結果です):
# curl -XPUT http://localhost:9200/mytest/test/1 -d '{ "title":"memo", "text":"ほげほげ" }'

{"_index":"mytest","_type":"test","_id":"1","_version":1,"created":true}


id = 1 のデータとして、title = "memo", text = "ほげほげ" の JSON データを Index = mytest, Type = test で登録しました。次にこのデータを GET メソッドで検索します:
# curl -XGET http://localhost:9200/mytest/test/_search -d '{ "query": { "match": { "title":"memo" } } }'
{"took":54,"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":"ほげほげ"}}]}}


title = "memo" のデータを mytest/test で検索した所、"text" = "ほげほげ" の期待通りの結果が得られました!(ただし、この時点ではまだ Kuromoji を使っていません) 動作確認ができたので、このデータを削除しておきます:
# curl -XDELETE http://localhost:9200/mytest/test/1
{"found":true,"_index":"mytest","_type":"test","_id":"1","_version":1}

ElasticSearch が正しく導入できて、動作も確認できた所で Kuromoji プラグインを導入して ElasticSearch を再起動します:
# /usr/share/elasticsearch/bin/plugin --install elasticsearch/elasticsearch-analysis-kuromoji/2.2.0
# /etc/init.d/elasticsearch restart

そして Kuromoji を有効にして、再度簡単な動作確認をしてみます。まずは新しいインデックスを作成して、Kuromoji をアナライザとして指定します:
# curl -XPUT http://localhost:9200/kuromoji_sample -d '{ "index": { "analysis": { "tokenizer": { "kuromoji_user_dict" : { "type":"kuromoji_tokenizer" } }, "analyzer": { "analyzer": { "type":"custom", "tokenizer": "kuromoji_user_dict" } } } } }'
{"acknowledged":true}

この新しく作成したインデックスに対して日本語文字列を POST して、形態素解析が有効になっているかどうかを確認します:
# curl -XPOST 'http://localhost:9200/kuromoji_sample/_analyze?analyzer=analyzer&pretty' -d '東京スカイツリー'
{
"tokens":[{
"token":"東京",
"start_offset":0,
"end_offset":2,
"type":"word",
"position":1
},{
"token":"スカイ",
"start_offset":2,
"end_offset":5,
"type":"word",
"position":2
},{
"token":"ツリー",
"start_offset":5,
"end_offset":8,
"type":"word",
"position":3
}]
}

「東京スカイツリー」が3つの単語に分割できていることがわかります。これが kuromoji による拡張機能です。


この kuromoji を使ったインデックスを ElasticSearch のデフォルトアナライザとして指定し、ElasticSearch を再起動します:
# vi /etc/elasticsearch/elasticsearch.yml
  :
index.analysis.analyzer.default.type: custom
index.analysis.analyzer.default.tokenizer: kuromoji_user_dict
  :
# /etc/init.d/elasticsearch restart

では改めて2つの日本語データを登録しておきます:
# curl -XPUT http://localhost:9200/kuromoji_sample/test/1 -d '{ "title":"メモ1", "text":"カレーは飲み物" }'
{"_index":"kuromoji_sample","_type":"test","_id":"1","_version":1,"created":true}

# curl -XPUT http://localhost:9200/kuromoji_sample/test/2 -d '{ "title":"メモ2", "text":"カレーライスは和食" }' {"_index":"kuromoji_sample","_type":"test","_id":"2","_version":1,"created":true}

そして、まずは「カレー」で検索してみます:
# curl -XGET http://localhost:9200/kuromoji_sample/test/_search -d '{"query":{"match":{"text":"カレー"}}}'
{
"took":67,"timed_out":false,"_shards":{
"total":5,"successful":5,"failed":0
},"hits":{
"total":1,"max_score":0.15342641,"hits":[{
"_index":"kuromoji_sample","_type":"test","_id":"1","_score":0.15342641,"_source":{
"title":"メモ1","text":"カレーは飲み物"
}
}]
}
}

正しく「カレーは飲み物」のデータがヒットすることが確認できます。気づいていただきたいのは、この時に2番目の「カレーライスは和食」のデータがヒットしていないということです。Kuromoji は「カレー」と「ライス」ではなく、「カレーライス」という単語を認識しているのだと想像できます。

次に「カレーは」で検索します:
# curl -XGET http://localhost:9200/kuromoji_sample/test/_search -d '{"query":{"match":{"text":"カレーは"}}}'
{
"took":8,"timed_out":false,"_shards":{
"total":5,"successful":5,"failed":0
},"hits":{
"total":2,"max_score":0.2169777,"hits":[{
"_index":"kuromoji_sample","_type":"test","_id":"1",
"_score":0.2169777,"_source":{
"title":"メモ1","text":"カレーは飲み物"
}},{
"_index":"kuromoji_sample","_type":"test","_id":"2",
"_score":0.02250402,"_source":{
"title":"メモ2","text":"カレーライスは和食"
}}]
}
}

2つのデータがヒットしています。ここでは "_score" の値に注目します。

_id = 1 のデータでは「カレーは飲み物」という7文字のうち4文字が一致しているため、そのスコアが高くなっています。一方、_id = 2 のデータでは「カレーライスは和食」という9文字のうち「カレー」という3文字と「は」という1文字しか一致していないこともあり、そのスコアが低くなっています。その結果、前者の方がより高い精度で一致していると判断されていることになります。これによってスコア付きの日本語検索も有効に行われていることが分かります。


結構簡単に日本語検索エンジンが作れてしまいました。ElasticSearch は REST でデータの読み書きができるし、Input/Output のフォーマットが JSON なので、プログラマ的にも便利で楽しそうな検索エンジンです。