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

Rails Webook

自社のECを開発している会社で働いています。Rails情報やサービスを成長させる方法を書いていきます

RailsでSonspotを使って全文検索を行う

Rails Model Rails中級 検索

f:id:nipe880324:20150221125622j:plain:w480
Photo by Flickr: Image Editor's Photostream

Sunspotは、オープンソースの全文検索システムのSolr(ソーラー)を使って、幅広い記述でパワフルな全文検索ができるRubyライブラリです。
商用ではSolrを立てる必要があります。開発環境では開発用のSolrサーバーを使います。

動作確認

  • Rails 4.2.0
  • Ruby 2.1.0
  • sunspot_rails 2.1.1
  • sunspot_solr 2.1.1

目次

  1. Sunspotのインストール
  2. Sunspotの基本的な使い方
  3. リインデックス(reindex)


1. Sunspotのインストール

Gemfileに追加します。

# Gemfile
gem 'sunspot_rails'

group :development, :test do
  # 開発環境用のSolrディストリビューション
  gem 'sunspot_solr'
end


バンドルを実行します。

bundle install


SunspotのSolrへの接続情報を設定するファイルを作成します。

bin/rails g sunspot_rails:install
  create  config/sunspot.yml


2. Sunspotの基本的な使い方

全文検索のデモ用にProductモデルとCategoryモデルを作成します。

bin/rails g model Product name:string desc:text category_id:integer
bin/rails g model Category name:string
bin/rake db:migrate


リレーションを追加します。

# app/model/category.rb
class Category < ActiveRecord::Base
  has_many :products
end

# app/model/product.rb
class Product < ActiveRecord::Base
  belongs_to :category
end


検索確認のためにデータを作成します。

# db/seeds.rb
category1 = Category.create! name: 'デスクトップパソコン'
category1.products.create! name: "高いパソコン", desc: "高いだけありHigh Specなパソコンです"
category1.products.create! name: "安いパソコン", desc: "とにかく安さだけを追求したパソコンです"

category2 = Category.create! name: 'ノートパソコン'
category2.products.create! name: "小さいノートPC", desc: "小さいノートPCです"
category2.products.create! name: "大きいノートPC", desc: "大きいノートPCです"
category2.products.create! name: "High SpecノートPC", desc: "性能がよいノートPCです"

category3 = Category.create! name: "スマホ"
category3.products.create! name: "High Specスマホ", desc: "High Specなスマホです"
category3.products.create! name: "普通のスマホ", desc: "スマホです"


データを入れます。

bin/rake db:seed


では、ここからSunspotを使うように設定をしていきます。

まず、全文検索を行いたいクラスにsearchableブロックを追加します。
今回はProductクラスを全文検索できるようにします。

class Product < ActiveRecord::Base
  belogns_to :category

  searchable do
    text :name, :desc

    integer :category_id
    time :created_at
  end
end

textフィールドは全文検索されます。integerstringなどの他のフィールドはクエリをスコープするために使われます。


そして、開発環境用のSolrディストリビューション(sunspot_solr)を起動させます。

// バックグラウンド
bin/rake sunspot:solr:start  // Solrを起動させる
bin/rake sunspot:solr:stop   // Solrを停止させる

// フォアグラウンド
bin/rake sunspot:solr:run    // Solrを起動させる


では、全文検索を行います。

$ bin/rails c

# Productのtextフィールド(name, descカラム)に"High Spec"を含んでいるすべての商品を検索する
search = Product.search { fulltext "High Spec" }
products = search.results
products.count #=> 3


# category_idが1か2で、'pizza'を含んでいて、1週間以内に作成された、2ページ目の商品を検索する
search = Product.search do
  fulltext "High Spec"
  with(:category_id, 1)
  with(:created_at).greater_than(1.week.ago)
end
products = search.results
products.count #=> 1


# カテゴリ毎に存在する商品数を取得する(facet)
search = Product.search do
  fulltext 'High spec'
  facet :category_id
end

search.facet(:category_id).rows.each do |facet|
  puts "Category #{facet.value} has #{facet.count} products"
end
# =>
# Category 1 has 1 products
# Category 2 has 1 products
# Category 3 has 1 products

・実施にはコントローラー内で上記のように記載すれば、実際に検索を行うことができます。

・他にもページネーションや複数の値の検索などさまざな検索方法は、Sunspot - GitHubを参照してください。


production環境でSunspotを実行する場合は、別途Solrサーバーを立て、sunspot.ymlを適切に設定する必要があります。

また、test環境で実行する場合は、下記のコマンドでSolrの起動と停止をしてください。

// solrを起動
bundle exec sunspot-solr start -p 8981
// RSpec(テスト)を実行
bundle exec rake spec
// solrを停止
bundle exec sunspot-solr stop


3. リインデックス(reindex)

Railsを使っている場合、オブジェクトはsaveコールバックによりSolrに自動的にインデックスされます。

その他にも、手動でリインデックスを実行する方法があります。

# クラス自体をインデックスする
Product.reindex
Sunspot.commit


# 複数のオブジェクトをインデックスする
Sunspot.index [product1, product2]
Sunspot.commit


# 自動的にコミットされる
Sunspot.index! [product1, product2]


もし、searchableブロック内のコードを修正した場合、すべてのオブジェクトをリインデックスしなければなりません。
そういった時に、次のコマンドでリインデックスができます。

bin/rake sunspot:solr:reindex


以上です。