railsから全文検索エンジンelasticsearchを利用する
ElasticSearchとは
ElasticSearchはSolrと同じApache Lucene上で稼働するオープンソースの全文検索システムです。
ElasticSearchの特徴としては、REST APIが整備されていて、JSONですべてやり取りできるところです。
準備
ElasticSearchはJavaで動作するので事前にJavaのインストールが必要です。
ElasticSearchのインストールはMacならbrewがあるので簡単です。
$ brew install elasticsearch
WindowsでもZipをダウンロードして、batファイル叩くだけだったので楽です。
ElasticSearchには様々なプラグインが用意されており、その中に日本語対応の物も用意されています。
kuromojiを用いたelasticsearch-analysis-kuromojiを使います。
プラグインのインストールも簡単で用意されているplugin
コマンドにgitの短縮アドレスを渡して叩くだけです。
(バージョン指定は適宜最新のものを参照してください)
$ plugin --install elasticsearch/elasticsearch-analysis-kuromoji/1.5.0
これでkuromojiをプラグインとして利用可能となりました。
日本語対応させる際に、後述するrailsのmodelでフィールド毎にAnalyzerとしてkuromojiを指定することも出来ますし、デフォルトのAnalyzerとして利用したければ設定ファイル(macなら/usr/local/opt/elasticsearch/config/elasticsearch.yml
)に以下を追記して指定することも可能です。
index.analysis.analyzer.default.type: custom
index.analysis.analyzer.default.tokenizer: kuromoji_tokenizer
ブラウザからElasticSearchの状態を確認できるプラグインも複数用意されています。
今回は基本的なelasticsearch-headを導入してみます。
$ plugin --install mobz/elasticsearch-head
elasticsearch-headプラグイン導入後はhttp://localhost:9200/_plugin/head/
にアクセスすることでブラウザから様々な確認が出来るようになります。
サンプルRailsアプリ
ElasticSearchを扱うためのサンプルアプリを作成します。
bundle init
してGemfile
にrails
追加して'bundle exec rails new
します。
全文検索を試したいので、ニュースの記事を扱うようにしてみます。
記事のモデル名をarticleにして、タイトルと本文を持つようにしてみました。
$ bundle exec rake db:create
$ bundle exec rails g scaffold article title:string body:text
$ bundle exec rake db:migrate
連携
RailsとElasticSearchとの連携にはtireを使います。
Gemfile
にgem 'tire'
を追加してbundle intall
します。
次にmodelにElasticSearchとの連携を記述します。
app/models/article.rb
class Article < ActiveRecord::Base
include Tire::Model::Search
include Tire::Model::Callbacks
mapping do
indexes :title, analyzer: :kuromoji
indexes :body, analyzer: :kuromoji
end
def self.search(params)
tire.search(load: true) do
query {
string "body:#{params[:search]} title:#{params[:search]}"
} if params[:search].present?
end
end
end
ControllerはArticle.all
の呼び出しをElasticSearchからの検索に変更します。
app/controllers/articles_controller.rb#index
def index
@articles = Article.search(params)
# @articles = Article.all
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 %>
<%= link_to 'clear', articles_path %>
これで
http://localhost:3000/articles
にアクセスして適当にニュース記事のデータを突っ込んで、検索窓にワードを打ち込めば検索可能になっています。