Sunspot Solr Search in Ruby On Rails

For using solr search in ruby on rails application. We have to use some ruby libraries that intereacts with the solr search So sunspot is on of the good library for working with solr search.

These gems are required to use in gemfile to install the sunspot libary.

gem ‘sunspot_rails’
gem ‘sunspot_solr’ # optional pre-packaged Solr distribution for use in development

Bundle it!
bundle install

Generate a default configuration file:
rails generate sunspot_rails:install

If sunspot_solr was installed, start the packaged Solr distribution with:
bundle exec rake sunspot:solr:start # or sunspot:solr:run to start in foreground

Setting Up Objects
Add a searchable block to the objects you wish to index.

Example : 1

class Article < ActiveRecord::Base
  has_many :posts
  searchable do
    text :title, :body
    text :posts do
      posts.map { |post| post.body }
    end

    boolean :featured
    integer :blog_id
    integer :author_id
    integer :category_ids, :multiple => true
    double  :average_rating
    time    :published_at
    time    :expired_at

    string  :sort_title do
      title.downcase.gsub(/^(an?|the)/, ”)
    end
  end
end

# Use that in controller
Post.search do
  fulltext ‘best pizza’
  with :blog_id, 1
  with(:published_at).less_than Time.now
  order_by :published_at, :desc
  paginate :page => 2, :per_page => 15
  facet :category_ids, :author_id
end

Example : 2
class Product < ActiveRecord::Base
  acts_as_taggable
  belongs_to :category
  belongs_to :sub_category
  belongs_to :child_sub_category, class_name: “SubCategory”
  # title is the column of products table
  searchable do
    text :title
    text :category do
      category.title
    end
    text :sub_category do
      sub_category.title
    end
    text :child_sub_category do
      child_sub_category.title
    end
    text :tags do
      tags.map { |tag| tag.name }
    end
  end

# Use that in controller
search = Product.search do
  fulltext params[:q]
end
@search = search.results

Example : 3
In this example, you can find there is the association between product and store. In relationship, there is store has_many products and product belongs_to store. If you wants to show contents from products table based on the search from stores table columns. Than you can follow the below way of structure

class Product < ActiveRecord::Base
  belongs_to :store
  searchable do
    text :title
    text :store do
      #Indexing stores columns for searching data
      [store.city, store.state, store.landmark, store.address, store.pin_code]
    end
    text :category do
      category.title
    end
    text :sub_category do
      sub_category.title
    end
    text :child_sub_category do
      child_sub_category.title
    end
    text :tags do
      tags.map { |tag| tag.name }class Product < ActiveRecord::Base
    end
  end
end

1 # Use that in controller
search = Product.search do
   # I am only searching from store columns and retriving the list of products
   fulltext params[:q], {:fields => :store}
   paginate :page => params[:page], per_page: 15
end
@search = search.results


2 # Use that in controller
search = Product.search do
      # This default query is searching from all the respected columns those are in searchable block of products
      fulltext params[:q]
      # We are filtering the data using location params. So whatever data we got from “fulltext params[:q]” that is being filtered by store attr (store.city, store.state, store.landmark, store.address, store.pin_code)
      fulltext params[:location], {:fields => :store}
      paginate :page => params[:page], per_page: 15
end
@search = search.results

Example : 4
In this example, you can find there is the association between product and store. In relationship, there is store has_many products and product belongs_to store. We are doing search from columns of stores table and providing relevant products. 

We are using join because we wants to filter the result using individual columns of store model as mentioned in Query 1. 
In this example, you can find
Query. 1
fulltext params[:pin_code], {fields: :pin_code}

Also we can combine and search them from controller as mentioned in Query.2

Query. 2
# It is filtering data of products using [:city, :landmark, :address, :state] that is present in stores table
fulltext params[:location], {
    fields: [:city, :landmark, :address, :state]
  }

class Product < ActiveRecord::Base
  belongs_to :store
  # Setting Up Objects
  searchable do
    integer :store_id
    text :title
    join(:city, :target => Store, :type => :text, :join => { :from => :id, :to => :store_id })
    join(:state, :target => Store, :type => :text, :join => { :from => :id, :to => :store_id })
    join(:landmark, :target => Store, :type => :text, :join => { :from => :id, :to => :store_id })
    join(:address, :target => Store, :type => :text, :join => { :from => :id, :to => :store_id })
    join(:pin_code, :target => Store, :type => :text, :join => { :from => :id, :to => :store_id })
    # text :store do
    #   [store.city, store.state, store.landmark, store.address, store.pin_code]
    # end
    text :category do
      category.title
    end
    text :sub_category do
      sub_category.title
    end
    text :child_sub_category do
      child_sub_category.title
    end
    text :tags do
      tags.map { |tag| tag.name }
    end
  end
end

1 # Use that in controller
search = Product.search do

  fulltext params[:q]
  fulltext params[:pin_code], {fields: :pin_code}
  fulltext params[:location], {
    fields: [:city, :landmark, :address, :state]
  }
  paginate :page => params[:page], per_page: 15
end
@search = search.results


If you make a change to the object’s “schema” (code in the searchable block), you must reindex all objects so the changes are reflected in Solr:

bundle exec rake sunspot:reindex

# or, to be specific to a certain model with a certain batch size:
bundle exec rake sunspot:reindex[500,Post] # some shells will require escaping [ with [ and ] with ]

# to skip the prompt asking you if you want to proceed with the reindexing:
bundle exec rake sunspot:reindex[,,true] # some shells will require escaping [ with [ and ] with ]

If you are using Rails, objects are automatically indexed to Solr as a part of the save callbacks.

There are a number of ways to index manually within Ruby:

# On a class itself
Person.reindex
Sunspot.commit # or commit(true) for a soft commit (Solr4)

# On mixed objects
Sunspot.index [post1, item2]
Sunspot.index person3
Sunspot.commit # or commit(true) for a soft commit (Solr4)

# With autocommit
Sunspot.index! [post1, item2, person3]

About the author

Being the CEO and Founder of ClecoTech International, Mr. Ashish Prajapati is dedicated towards his aim of mentoring young startups into a full-fledged businesses. He is helping startups from America, Europe, India, and various other countries through proper guidance and the use of latest technologies to develop their innovation and ideas into definite realities.

Leave a Reply

Your email address will not be published.