Edited at

railsから全文検索エンジンelasticsearchを利用する

More than 5 years have passed since last update.


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してGemfilerails追加して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を使います。


Gemfilegem '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にアクセスして

適当にニュース記事のデータを突っ込んで、

検索窓にワードを打ち込めば検索可能になっています。