Elasticsearchを使ったRailsサンプルアプリケーションの作成


検索機能を実装するときによく使われているElasticsearchをRailsで使うためのサンプルアプリケーションの作成の手順を作りました。入門レベルです!


😼 Elasticsearchの導入

拙著『Elasticsearch 2.1 + Kibana 4.1 + Marvel のMacへのセットアップ』を良ければご参考ください。

🐞 Railsサンプルアプリケーション

Railsのサンプルアプリケーションを作成します。今回は Article(記事) のモデルをもつことにします。

# Railsアプリの作成
rails new elasticsearch_sample --skip-bundle
# フォルダを移動
cd elasticsearch_sample
# DBの作成
rake db:create
# article テーブルの定義を作成
bundle exec rails g scaffold article title:string body:text
# article テーブルを作成
bundle exec rake db:migrate

GemfileにElasticsearch用のgemを追加します。

# Gemfile
# Elasticsearch
gem 'elasticsearch-model', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
gem 'elasticsearch-rails', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'

追加したらターミナルで次のコマンドを実行してgemをインストールします。

bundle install --jobs=4 --path=vendor/bundle

🗻 ModelにElasticsearchを使うための設定

次にArticleモデルにElasticsearchを使うための設定をします。

# app/models/article.rb
class Article < ActiveRecord::Base
include ArticleSearchable
end

今回はconcernにElasticsearchに関する処理を切り出します。

# app/models/concerns/article_searcable.rb
module ArticleSearchable
extend ActiveSupport::Concern
included do
include Elasticsearch::Model
# インデックスするフィールドの一覧
INDEX_FIELDS = %w(title body).freeze
# インデックス名
index_name "es_sample_article_#{Rails.env}"
# マッピング情報
settings do
mappings dynamic: 'false' do # 動的にマッピングを生成しない
indexes :title, analyzer: 'kuromoji', type: 'string'
indexes :body, analyzer: 'kuromoji', type: 'string'
end
end
# インデックスするデータを生成
# @return [Hash]
def as_indexed_json(option = {})
self.as_json.select { |k, _| INDEX_FIELDS.include?(k) }
end
end
module ClassMethods
# indexの作成メソッド
def create_index!
client = __elasticsearch__.client
client.indices.delete index: self.index_name rescue nil
client.indices.create(index: self.index_name,
body: {
settings: self.settings.to_hash,
mappings: self.mappings.to_hash
})
end
end
end

インデックス名には環境情報をつけておきます。

理由はlocalでのテストをしやすくするためです。

🐮 index作成のRakeタスクを作成

続いてindexを作成するRakeタスクを作ります。

まずはRakeタスクを作成するために、次のコマンドをターミナルで実行します。

rails g task elasticsearch

作成されたRakeタスクを以下のように変更します。

# lib/tasks/elasticsearch.rake
namespace :elasticsearch do
desc 'Elasticsearch のindex作成'
task :create_index => :environment do
Article.create_index!
end
desc 'Article を Elasticsearch に登録'
task :import_article => :environment do
Article.import
end
end

ではインデックスを作成します。

bundle exec rake elasticsearch:create_index

http://localhost:9200/_plugin/head/ にアクセスして「es_sample_article_development => info => Metadata」
の中身が以下のようになっていたら成功です!

ちなみに、curlコマンドでもマッピングを確認できます。
ターミナルで次のコマンドを実行してみてください。

curl -XGET 'localhost:9200/es_sample_article_development/_mapping/article?pretty=true'
{
"es_sample_article_development" : {
"mappings" : {
"article" : {
"dynamic" : "false",
"properties" : {
"body" : {
"type" : "string",
"analyzer" : "kuromoji"
},
"title" : {
"type" : "string",
"analyzer" : "kuromoji"
}
}
}
}
}
}

🤔 サンプルデータの作成

サンプルデータを作成します。

# db/seeds.rb
ActiveRecord::Base.transaction do
# ===========================
# 記事(Article)
# ===========================
Article.delete_all
10.times do |idx|
Article.create!(
title: "タイトル #{idx}",
body: "本文 #{idx}"
)
end
end

Elasticsearchにデータを登録します。

# サンプルデータの生成
bundle exec rake db:seed
# Elasticsearchへの登録
bundle exec rake elasticsearch:import_article

http://localhost:9200/_plugin/head/ から「Structured Query」を選択していろいろいじるとデータが格納されていることが分かると思います!

ちなみに、rails console からでもいろいろ試せるのでぜひいろいろ遊んでみてください!

Article.search('9').results.count
#=> 1
Article.search('9').results.first
#=> #<Elasticsearch::Model::Response::Result:0x007fb7ebac0a08 @result=#<Hashie::Mash _id="10" _index="es_sample_article_development" _score=1.1972358 _source=#<Hashie::Mash body="本文 9" created_at="2016-01-03T11:02:46.578Z" id=10 title="タイトル 9" updated_at="2016-01-03T11:02:46.578Z"> _type="article">>
Article.search(query: {term: {title: "5"} }).records.first
#=> Article Load (0.1ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" = 6
#=> #<Article id: 6, title: "タイトル 5", body: "本文 5", created_at: "2016-01-03 11:02:46", updated_at: "2016-01-03 11:02:46">

🏈 とりあえず一覧の検索を実装

articles_controllerindex を次のように変更。

# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def index
@articles =if params[:search]
Article.search(params[:search]).records
else
Article.all
end
end
end

viewも以下を追加。

# app/views/articles/index.html.erb
<%= form_tag articles_path, :method => :get do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag 'Search', :name => nil %>
<% end %>

http://localhost:3000/articles にアクセスすれば検索できると思います!

🎳 参考リンク

🖥 VULTRおすすめ

VULTR」はVPSサーバのサービスです。日本にリージョンがあり、最安は512MBで2.5ドル/月($0.004/時間)で借りることができます。4GBメモリでも月20ドルです。 最近はVULTRのヘビーユーザーになので、「ここ」から会員登録してもらえるとサービス開発が捗ります!

📚 おすすめの書籍