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}
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[: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]