Herokuで動いているRailaアプリに全文検索を導入しようとしてElasticsearchを検討したけどローカルですら導入につまづいてしまい、昔ちょっと触ったことがあるSolrにしたら余裕で導入できました。という話です。慣れの問題かも?

(いやーElasticsearchむずかしかったと思うんだわ…)

ローカル

% brew install solr

でおk。

Herokuへの導入

heroku addons:create websolr:staging-20 -a yourappname

でおk。グレード?は必要に応じて。最安では20ドルです。

Railsへの導入

sunspot gemが大変便利です。

gemの追加とbundle installして、

1gem 'sunspot_rails'
2gem 'sunspot_solr'

generateして、

% rails generate sunspot_rails:install

あ、ついでにローカルはSolrもスタートさせておきましょう。終わったら落としたいのでrake sunspot:solr:runでフォアグラウンドで動かしておきます。

bundle exec rake sunspot:solr:run

モデルの設定

検索対象にしたいモデルに設定用のコードを書きます。どのカラムをどんなデータタイプとして検索対象にするかを指定できます。子レコードの内容も親の検索内容とすることも簡単です。

Rubyのコードで書けるのでとても柔軟です。

1# ユーザーの全員検索とかないかもしれないけど
2class User < ActiveRecord::Base
3  searchable do
4    text :name, :email
5  end
6end
 1class Diary < ActiveRecord::Base
 2  belongs_to :user
 3
 4  searchable do
 5    text :content
 6    text :user_name do
 7      user.name
 8    end
 9  end
10end

みたいな感じですね。

検索方法

1Diary.search { fulltext 'こんにちは' }

searchにブロックを渡して検索します。重み付けなどありますが、シンプルにやるならfulltextに検索ワードを渡すだけでOKです。

Solrへの登録

インデックシングと呼ぶのかな?データの登録をしないと検索しても何も返ってきません。

初回の登録はモデルごとにreindexするか、sunspotのrakeタスクでまとめて登録しちゃいましょう。

1User.reindex
2Diary.reindex

みたいにrails consoleから実行したり、

% bundle exec rake sunspot:reindex

として、全体を対象にすればOKです。

また、日々データが登録・更新されるような場合にはそのタイミングでデータを再度インデックスする必要がありますので、after_saveなどのコールバックとdelayed_jobなどのジョブを活用して都度インデックスしてあげましょう。

1class User < ActiveRecord::Base
2  after_save :update_index
3
4  def update_index
5    Sunspot.index(self)
6  end
7end

すでにデータが存在する本番環境へのデプロイの場合には、デプロイ後にインデックス登録のrakeタスクを走らせたほうがいいでしょう。じゃないと何も検索にかかりません。ただし、データ量が多い場合は時間がそれなりにかかりますので利用者の少ない時間帯がよいかと。

データ量にもよりますが、再インデックスのrakeタスクは夜間バッチで勝手に動くようにしておいてもよいと思います。