読者です 読者をやめる 読者になる 読者になる

maeshimaの日記

メモ書きです

sunspot_rails

sunspot_rails/README.rdoc at master from outoftime/sunspot - GitHubの意訳。

Sunspot::Rails は Sunspot の Solr 検索を Rails に統合するためのプラグイン。下記のような機能を提供する。

  • config/sunspot.yml で sunspot の設定が出来る
  • ActiveRecord を拡張してインデックスの作成/設定と検索とを楽にする
  • ActiveRecordのオブジェクトが保存されたときや削除されたときに自動でインデックスも作成/削除される(機能をオフにすることも出来る)
  • 自動で各リクエストの最後に Solr の変更をコミットする(機能をオフにすることも出来る)
  • 孤立したドキュメントを探して直してインデックスを再構築するメソッドを提供
  • Solr インスタンスを sunspot.yml の設定を利用しつつ起動したり中止したり出来る

Rails の 2.3 と 3.0 でテストされている。

インストール

Gemfile

gem 'sunspot_rails'

Sunspot::Rails を使う

Solr スキーマを修正したい場合、RAILS_ROOT/solr/conf を作って、Solr gem の solr/solr/conf ディレクトリの中身をコピーする。ファイルが正しい場所に存在する場合、Sunspot::Rails はそれを検知して Solr にその設定を使うように指示する。schema.xml を修正したときには注意すべき。Sunspot relies on the field naming scheme in the packaged schema file.

Solr インスタンスを開始するには下記のようにする。

rake sunspot:solr:start

Sunspot と一緒にパッケージされている Solr インスタンスは開発用であり、production では推奨されない。詳しくはSunspot のドキュメント読んで。

検索とインデックス作成用の設定

検索とインデックス作成用の設定は下記のようにする。

class Post < ActiveRecord::Base
  searchable do
    text :title, :body
    integer :blog_id
    time :updated_at
    string :sort_title do
      title.downcase.sub(/^(an?|the) /, '')
    end
  end
end

ブロック中に何が出来るのかは Sunspot.setup のドキュメントを参照のこと。

インデックスの更新

保存したときに自動でインデックスの更新、削除したときに自動でインデックスの削除をするのを下記のようにすることでやめさせることが出来る。

class Post < ActiveRecord::Base
  searchable :auto_index => false, :auto_remove => false do
    # setup...
  end
end

auto_remove は推奨されない。インデックスを削除せずにオブジェクトを削除すると、孤立したドキュメントがインデックスに残ってしまう。これはよくない。auto_indexをオフにするのは、手動でインデックスを更新すればいいので問題ない。

もしインデックス変更のフックをオフにした場合、下記のように直接インデックスを変更できる

post = Post.create
post.index
post.remove_from_index

committing

Solr 内でデータが変更されたとき、それは最初にメモリに入れられる。そのときに走っている検索用のインスタンスは変更したデータを使えない。Solr にコミットすると、変更をディスクに書き込んで、新しい検索用のインスタンスを作る。この操作はかなりコストが高い。ドキュメントが作成されるか削除されるかしたときに毎回コミットするようなことをせずに、Sunspot::Rails は各リクエストの最後にコミットする。すぐにコミットしたい場合は下記のように!をつける。

post = Post.create
post.index!
# this is the same as...
post.index
Sunspot.commit

コントローラのリクエストの外のコンテキストのテストを書くときには、これらの二つのどちらかやり方を使う。

検索

こんな風にする

Post.search do
  with :blog_id, 1
  with(:updated_at).greater_than(Time.now - 2.weeks)
  order :sort_title, :asc
  paginate :page => 1, :per_page => 15
end

ブロック中で使える全てのオプションを知りたければ Sunspot.serach のドキュメントを見るべし。

ID の検索

検索したときに、モデルのIDだけ取得したいときがあるかもしれない。search_ids メソッドを使うと、search と同じ検索の仕方で、戻り値はIDの配列。

複数テーブルの検索

Sunspot は検索の対象が一つなのか二つ以上なのか知らない。Sunspot::Rails はこのへんサポートしてないので Sunspotのインタフェースを使う。

Sunspot.search(Post, Comment) do
  with :blog_id, 1
  order :created_at, :asc
end

詳しくは Sunspot のドキュメントを参照のこと。

検索機能を mixin で追加する

SunSpot は一箇所に設定を置く必要がない。Sunspot.setup メソッドは二回以上呼び出すことが出来る。これはmixinで検索機能を加えるときに使える。例えば追加の検索フィールドを、Ratable モジュールを mixin したクラスに加えたい場合は下記のようにする

module Ratable
  def self.included(base)
    if base.searchable?
      base.searchable do
        float :average_rating do
          ratings.average(:value)
        end
      end
    end
  end
end

base.serachable? は検索の設定がすでにされており、追加で設定可能かどうかを返す。上記のコードを使うには、 mixin する前に既に searchable を設定している必要がある。

ユーティリティメソッド

モデルに紐付いたインデックスを再構築するには下記のようにすることができる

Post.reindex

もし何らかの理由でモデルがDBから削除され、インデックスからは削除されなかった場合、それらは孤立する。インデックスにあるけどDBにないモデルのIDを得るために、 index_orphans メソッドが用意されている。インデックスからそれらを削除するために、 clean_index_orphans メソッドが用意されている。いずれのメソッドも使う必要があるような状況にするべきではない。

Rspec で Solr を使ったテストをする

ActiveRecord のモデルを扱う際に、sunspot と Solr の統合をオフにするにはまず require 'sunspot/rails/spec_helper' とする。それから下記のように disconnect_sunspot メソッドを使う

require 'sunspot/rails/spec_helper'

describe Post do
  disconnect_sunspot

  it 'should have some behavior'
    # ...
  end
end

上記の examples はすべての Sunspot の呼び出しが stub out される。Sunspot#serach メソッドが stub 化された、結果が何も入っていない search オブジェクトを返すようになる。

もっとくわしく

Sunspot のドキュメントを読むべき。Sunspot::Rails は Sunspot のラッパなので、Sunspot::Rails の機能はすべて Sunspot に実装されている。

Sunspot 1.2.rc3 - Solr-powered search for Ruby objects - API Documentation