Elasticsearch / ActiveRecord / Rails / Ruby

この記事はElasticsearch Advent Calendar 2014の3日目です。

2日目は@ariarijpさんの「入門記事:ElasticSearch1.4.0とKibana4.0.0の環境構築」でした。おつかれさまでした。

ではさっそくはじめましょう。

elasticsearch-rails Gemを追加する

Rails Consoleを起動する前にまずGemfileに

gem 'elasticsearch-model'
gem 'elasticsearch-rails'

を追加します。

bundle installelasticsearch-railsをインストールしたら、Rails Consoleを起動します。

% rails c

Elasticsearch::Modelを組み込む

最初に扱いたいデータのActiveRecordモデルクラスでElasticsearch::Modelincludeします。

> class Blog::Site; include Elasticsearch::Model; end
=> Blog::Site (call 'Blog::Site.connection' to establish a connection)

これでBlog::Siteモデルに一通りメソッドが追加されます。

Elasticsearchにデータをインポートする

Elasticsearchへのインポートにはimportメソッドを使います。

> Blog::Site.__elasticsearch__.import
# Blog::Site Load (1.9ms)  SELECT  `blog_sites`.* FROM `blog_sites`   ORDER BY `blog_sites`.`id` ASC LIMIT 1000
=> 0

続いてElasticsearchに問い合わせてインポート結果を確認します。

マッピングを確認する

Elasticsearchに問い合わせるにはインデックス名とタイプ名が必要なので、まずはそちらを確認してみます。

> Blog::Site.__elasticsearch__.index_name
"blog-sites"
> Blog::Site.__elasticsearch__.document_type
"site"

blog-sitesインデックスのsiteタイプとして登録されたようです。

この名前がわかればElasticsearchのAPIにアクセスできるので、インポート結果を確認してみましょう。

マッピングを確認する方法はいくつかあるのですが、今回はperform_requestを使います。

> Blog::Site.__elasticsearch__.client.perform_request(
  :get,
  'blog-sites/site/_mapping'
).body
=> {"blog-sites"=>
  {"mappings"=>
    {"site"=>
      {"properties"=>
        {"created_at"=>{"type"=>"date", "format"=>"dateOptionalTime"},
         "description"=>{"type"=>"string"},
         "id"=>{"type"=>"long"},
         "language"=>{"type"=>"string"},
         "title"=>{"type"=>"string"},
         "updated_at"=>{"type"=>"date", "format"=>"dateOptionalTime"},
         "user_id"=>{"type"=>"long"}}}}}}

各プロパティがlong, string, date型で登録されていますね。

件数を取得する

続いて件数も見てみましょう。

> Blog::Site.__elasticsearch__.client.perform_request(
  :get,
  'blog-sites/site/_count'
).body
=> {"count"=>3, "_shards"=>{"total"=>5, "successful"=>5, "failed"=>0}}

データを確認する

id=1のデータの中身も見てみます。

> Blog::Site.__elasticsearch__.client.perform_request(
  :get,
  'blog-sites/site/1'
).body
=> {"_index"=>"blog-sites",
 "_type"=>"site",
 "_id"=>"1",
 "_version"=>1,
 "found"=>true,
 "_source"=>
  {"id"=>1,
   "user_id"=>11,
   "language"=>"ja",
   "title"=>"Railsブログ",
   "description"=>"Railsの技術ブログです",
   "created_at"=>"2014-11-07T09:32:46.000+09:00",
   "updated_at"=>"2014-11-07T09:32:46.000+09:00"}}

ちゃんとデータが取得できました。

フィルタで検索する

続いて検索をしてみましょう。検索にはsearchメソッドを利用します。

まずはtermフィルタを利用してlanguagejaのデータを検索してみます。

> Blog::Site.search(
  filter: {term: {language: 'ja'}}
).records.to_a
# Blog::Site Load (0.3ms)  SELECT `blog_sites`.* FROM `blog_sites`  WHERE `blog_sites`.`id` IN (2, 1)
=> [#<Blog::Site id: 2, user_id: 11, language: "ja", title: "Elasticsearchブログ", description: "Elasticsearchの技術ブログです", created_at: "2014-11-07 00:32:47", updated_at: "2014-11-07 00:32:47">,
 #<Blog::Site id: 1, user_id: 11, language: "ja", title: "Railsブログ", description: "Railsの技術ブログです", created_at: "2014-11-07 00:32:46", updated_at: "2014-11-07 00:32:46">]

2件のデータがヒットしました。

クエリで検索する

続いてmatchクエリtitleにElasticsearchを含むデータを検索してみましょう

> Blog::Site.search(
  query: {match: {title: 'Elasticsearch'}}
).records.to_a
# Blog::Site Load (0.2ms)  SELECT `blog_sites`.* FROM `blog_sites`  WHERE `blog_sites`.`id` IN (2)
=> [#<Blog::Site id: 2, user_id: 11, language: "ja", title: "Elasticsearchブログ", description: "Elasticsearchの技術ブログです", created_at: "2014-11-07 00:32:47", updated_at: "2014-11-07 00:32:47">]

ちゃんとElasticsearchのデータが検索できました。

アグリゲーションで集計する

次はtermsアグリゲーションlanguage毎の件数を集計してみます。

> Blog::Site.__elasticsearch__.search(
  {aggs: {agg: {terms: {field: :language}}}},
  search_type: :count
).response["aggregations"]
=> {"agg"=>{"buckets"=>[{"key"=>"ja", "doc_count"=>2}]}}

languageがjaのデータが2件という集計結果でした。

インデックスを削除する

一通り動作を確認したので、最後にインデックスを削除します。

> Blog::Site.__elasticsearch__.delete_index!
=> {"acknowledged"=>true}

削除したらこのままRails Consoleを抜けておしまいです。

まとめ

今回はElasticsearchをRailsから手軽に扱う方法をご紹介しました。

Elasticsearchに慣れた後でも、データベースのデータをサッとElasticsearchに入れて動作確認できると結構便利なのでそういった時にも参考にしていただければ良いかと思います。

もちろんやろうと思えばもっといろんなことができるので、その際はElasticsearchやElasticsearch-railsのドキュメントを見ながら色々試してみてください。

4日目は@tadyさんです。よろしくお願いします。

参考文献