Reputation: 1821
I am searching against title and description of Products. it works cool but all i need a search like to get a result precedence based. like in result products with title match comes first then description. Here is my controller code:
def products
scope = Product.joins(:vendor).enabled.includes(:vendor, :images)
# Make sure to select only available vendors
scope = scope.where("vendors.enabled = ?", true)
# Filter by vendor
if params[:vendor_id].present?
scope = scope.where(vendor_id: params[:vendor_id])
end
if params[:search].present?
scope = scope.filter(params[:search])
end
scope
end
and here is model. product.rb
def self.filter(search)
where("title ILIKE '%#{search}%' OR description ILIKE '%#{search}%'")
end
Upvotes: 1
Views: 418
Reputation: 11372
So the outcome of this will be that you have a set of Product
objects that match the search in one of their fields.
The missing part is that now you need to sort your results- you can do this as part of your query but it's relatively hard work and I would be inclined to do the work in Ruby.
I would start by generating a result score based on the number of occurrences of the search terms in your result, something like this:
def score_result( result, search_term )
score = result.title =~ search_term ? 5 : 0
score+= result.text =~ search_term ? 1: 0
end
Then you could apply that as a filter on your search:
if params[:search].present?
searchPattern = Regexp.new(params[:search])
scope = scope.filter(params[:search]).sort_by { | res | score_result(res, searchPattern) }
end
That should sort results where the term appears in both first, then ones where it appears only in the title, then ones where it appears only in the text.
A couple of notes of caution:
top hats and tails
- do you only want to match that exact phrase? Should you be split it up and then assign a score per word? If you do that, do you want to return results where the title or text contains and
as a search result? How do you weight them? If one word matches multiple times should that score as highly as different words matching once each?Upvotes: 1