keisyuのブログ

最近めっきりエンジニアリングしなくなった厄年のおじさんがIT技術をリハビリするブログ。

Elasticsearch 1.0 を使ってみた2。( perl からの利用と日本語全文検索 )

前回 Elasticsearch を利用してみて (Elasticsearch 1.0 を使ってみた。 - keisyuのブログ)検索に関する仕事を5年以上やってた経験があるだけに非常に便利な世の中になったもんだと感動しました。今回はPerlから利用して見る方法と日本語全文検索はどんな感じかを試してみたいと思います。

elasticsearch.pm

Elasticsearchのリファレンスに記載の通り (Elasticsearch.pm) cpanのモジュールがすでにあるようです。

$ cat cpanfile
requires 'Elasticsearch';
$ carton install
...
Successfully installed Elasticsearch-1.03
59 distributions installed

とりあえずリファレンス通りにやってみる

use strict;
use warnings;
use utf8;
use Elasticsearch;
use Data::Dumper;

my $e = Elasticsearch->new(
    nodes => '192.168.56.101:9200',
);

print Dumper $e->index (
    index   => 'myindex',
    type    => 'mytype',
    id      => 'doc3',
    body    => {
        'name' => 'Suzuki Ichiro',
        'comment' => 'this document was inserted by perl module!'
    }
);

print Dumper $e->get(
    index   => 'myindex',
    type    => 'mytype',
    id      => 'doc1'
);

print Dumper $e->search(
    index   => 'myindex',
    body    => {
        query => {
            match => { 'comment' => 'perl' }
        }
    }
);

実行すると期待通りの結果が応答されます。

$ carton exec -- perl es.pl
$VAR1 = {
          '_version' => 4,
          '_id' => 'doc3',
          '_type' => 'mytype',
          '_index' => 'myindex',
          'created' => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' )
        };
$VAR1 = {
          '_version' => 7,
          '_id' => 'doc1',
          '_source' => {
                         'comment' => 'Hello! Elasticsearch World!',
                         'age' => 40,
                         'name' => 'Yamada Taro'
                       },
          '_type' => 'mytype',
          '_index' => 'myindex',
          'found' => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' )
        };
$VAR1 = {
          'hits' => {
                      'total' => 1,
                      'hits' => [
                                  {
                                    '_source' => {
                                                   'comment' => 'this document was inserted by perl module!',
                                                   'name' => 'Suzuki Ichiro'
                                                 },
                                    '_id' => 'doc3',
                                    '_type' => 'mytype',
                                    '_score' => '0.11506981',
                                    '_index' => 'myindex'
                                  }
                                ],
                      'max_score' => '0.11506981'
                    },
          'timed_out' => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' ),
          '_shards' => {
                         'total' => 5,
                         'failed' => 0,
                         'successful' => 5
                       },
          'took' => 4
        };

日本語全文検索

それではとりあえず何も考えずに上のサンプルで日本語のドキュメントを投入して日本語検索してみましたがうまくいきませんでした。
このindexを定義するときにmappingを指定せず登録されたデータから自動的に生成しましたので日本語の形態素解析をするanalyzerとして定義がフィールドにされなかったからだと思います。これを明示的に指定してindexを生成して日本語で検索ができるようにしてみます。

今回は comment という要素に対して NGram のインデックスをmappingにて定義してみます。
Elasticsearchが標準で搭載するNgramのアナライザに関してはこの辺が参考になります。NGram Tokenizer

以下の要領でindexを再定義します。

use strict;
use warnings;
use utf8;
use Elasticsearch;
use Data::Dumper;

my $e = Elasticsearch->new(
    nodes => '192.168.56.101:9200',
);

print Dumper $e->indices->delete(
    index => 'myindex',

);

print Dumper $e->indices->create(
    index => 'myindex',
    body => {
        settings => {
            analysis => {
                analyzer => {
                    my_ngram_analyzer => {
                        tokenizer => 'my_ngram_tokenizer'
                    }
                },
                tokenizer => {
                    my_ngram_tokenizer => {
                        type => 'nGram',
                        min_gram => 2,
                        max_gram => 3,
                        token_chars => [ "letter", "digit" ]
                    }
                }
            }
        },
        mappings => {
            mytype => {
                properties => {
                    name    => { type => 'string'},
                    comment => { type => 'string', analyzer => 'my_ngram_analyzer'},
                    age     => { type => 'integer'}
                }
            }
        }
    }
);

データを投入して検索してみると正しく結果が応答されるはずです

print Dumper $e->index (
    index   => 'myindex',
    type    => 'mytype',
    id      => 'doc4',
    body    => {
        'name' => 'Takahashi Daisuke',
        'comment' => '日本語の検索が正しく動作するかの確認です。'
    }
);
# 投入した直後はヒットしない可能性があるので注意。
print Dumper $e->search(
    index   => 'myindex',
    body    => {
        query => {
            match => { 'comment' => '京都' }
        }
    }
);  # ヒットしない
print Dumper $e->search(
    index   => 'myindex',
    body    => {
        query => {
            match => { 'comment' => '検索' }
        }
    }
);   # ヒットする

HQの管理ツールからも検索が直接試せるのでここからでも確認できます。すごい便利!
f:id:keisyu:20140220005315j:plain:w300

Ngram ではなく 形態素解析にて検索したい場合はこの辺を参考にする。

以下の日本語形態素解析のpluginをインストールします。
elasticsearch/elasticsearch-analysis-kuromoji · GitHub

$ cd /usr/share/elasticsearch
$ sudo bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/2.0.0.RC1
$ sudo /sbin/service elasticsearch restart  # /_nodes/plugin?pretty にアクセスしてpluginインストール確認

疲れたのでまた今度にする。