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
して、
gem 'sunspot_rails'
gem 'sunspot_solr'
generateして、
% rails generate sunspot_rails:install
あ、ついでにローカルはSolrもスタートさせておきましょう。終わったら落としたいのでrake sunspot:solr:run
でフォアグラウンドで動かしておきます。
bundle exec rake sunspot:solr:run
モデルの設定
検索対象にしたいモデルに設定用のコードを書きます。どのカラムをどんなデータタイプとして検索対象にするかを指定できます。子レコードの内容も親の検索内容とすることも簡単です。
Rubyのコードで書けるのでとても柔軟です。
# ユーザーの全員検索とかないかもしれないけど
class User < ActiveRecord::Base
searchable do
text :name, :email
end
end
class Diary < ActiveRecord::Base
belongs_to :user
searchable do
text :content
text :user_name do
user.name
end
end
end
みたいな感じですね。
検索方法
Diary.search { fulltext 'こんにちは' }
search
にブロックを渡して検索します。重み付けなどありますが、シンプルにやるならfulltext
に検索ワードを渡すだけでOKです。
Solrへの登録
インデックシングと呼ぶのかな?データの登録をしないと検索しても何も返ってきません。
初回の登録はモデルごとにreindex
するか、sunspotのrakeタスクでまとめて登録しちゃいましょう。
User.reindex
Diary.reindex
みたいにrails console
から実行したり、
% bundle exec rake sunspot:reindex
として、全体を対象にすればOKです。
また、日々データが登録・更新されるような場合にはそのタイミングでデータを再度インデックスする必要がありますので、after_save
などのコールバックとdelayed_job
などのジョブを活用して都度インデックスしてあげましょう。
class User < ActiveRecord::Base
after_save :update_index
def update_index
Sunspot.index(self)
end
end
すでにデータが存在する本番環境へのデプロイの場合には、デプロイ後にインデックス登録のrakeタスクを走らせたほうがいいでしょう。じゃないと何も検索にかかりません。ただし、データ量が多い場合は時間がそれなりにかかりますので利用者の少ない時間帯がよいかと。
データ量にもよりますが、再インデックスのrakeタスクは夜間バッチで勝手に動くようにしておいてもよいと思います。