Reputation: 392
We use Sunspot Solr with our Rails 3.1 app. We have a location model that we are searching. Here's the code for the search
location_search = Location.search do
keywords params[:search][:keywords] if params[:search][:keywords].present?
with :category_ids, category_id if category_id.present?
unless params[:search][:keywords].present?
order_by :premium, :desc
end
if params[:search][:sort].present?
field, direction = params[:search][:sort].split('-')
else
order_by :score, :desc
order_by :random
end
paginate :page => params[:search][:page], :per_page => per_page
end
My question is how do I get locations to be randomized in the results while keeping the pagination the same? Meaning, I want to sort the results randomly (not by record creation date or name) but I want page 2 of the results to be the same list even if I refresh the page (and pass 2 to params[:search][:page]). Ideally, the order would stay the same for the current users session.
The reason for this is locations on our site pay to be premium so premium results should come first, but those who don't pay should be randomized so we aren't favoring locations because of the order they were created or their order based on name.
Thanks! Help is really appreciated.
Upvotes: 0
Views: 535
Reputation: 1059
You can use the same technique as I answered with here about a consistent random seed.
Sunspot supports using a random seed. See the docs here: https://github.com/sunspot/sunspot/wiki/Ordering-and-pagination#pagination-with-random-ordering
So what you would do (See my other answer for details) is generate and store a random number in the user session. Then use this number as a seed for your random retrieval method:
Sunspot.search(Post) do
paginate(:page => 2, :per_page => 15)
order_by(:random, :seed => session_specific_random_seed)
end
Upvotes: 0
Reputation: 76
Some time ago, I was also working on a paginated collection that had be configured to return a random sort order. I realized that because sunspot always sends Solr a random seed value, I would intermittently receive duplicate results between pages. In order to fix this, I thought it useful to be able to configure the seed value while searching.
The implementation I thought would make the most sense would retain the existing syntax specifications while also allowing a new parameter type to the order_by function.
For Example
Model.search do
order_by :random, :seed => 12345, :direction => :asc
end
I implemented this and it was merged into master for the sunspot_rails
gem with this pull request: https://github.com/sunspot/sunspot/pull/328
Upvotes: 3
Reputation: 186
You can retrieve a much larger page than needed, shuffle it predictably, and then cut it down to size. Perhaps something like this (Random is a ruby 1.9 class):
SUPER_PAGE_MULTIPLIER = 5
location_search = Location.search do
keywords params[:search][:keywords] if params[:search][:keywords].present?
with :category_ids, category_id if category_id.present?
unless params[:search][:keywords].present?
order_by :premium, :desc
end
if params[:search][:sort].present?
field, direction = params[:search][:sort].split('-')
else
order_by :score, :desc
# order_by :random
end
paginate :page => params[:search][:page] / SUPER_PAGE_MULTIPLIER, :per_page => per_page * SUPER_PAGE_MULTIPLIER
end
session[:seed] ||= rand(100000)
rng = Random.new(session[:seed])
too_many_results = location_search.results
too_many_results.shuffle!(rng)
results = too_many_results.slice((params[:search][:page] % SUPER_PAGE_MULTIPLIER) * per_page, per_page)
Upvotes: 0