Topic: How to find the 3 closest matches in a search using ranked terms

I'm a RoR noob so excuse me if I use incorrect terms.

I'm building a dog finder to help people choose the best dog breed for their lifestyle.

So I have created the Dog using Scaffold (could we say have I created a Dog model then?)

class CreateDogs < ActiveRecord::Migration
  def self.up
    create_table :skis do |t|
      t.string :breed
      t.integer :speed
      t.integer :size
      t.integer :friendly
      t.timestamps
    end
  end

speed is rated from 1-10 with 10 being fastest.
size is rated 1-10 with 10 being heaviest.
friendly is rated 1-10 with 10 being friendliest.

The breed: Golden Lab for instance has a score
speed = 5
size = 8
friendly = 10

I'm creating a form for users to fill in the range of attributes they are looking for, so they could be looking for breed with:

speed = 10
size = 5
friendly = 10

How would I return the top 3 breed matches for their search terms, using RoR?

I've been looking at the <=> operator, sort_by but I'm not sure how to string it all together. I thought it was a simple search at first - but all items need to be compared with each other.

Also how could I to add weighting to friendliness so it's more important than the other 2 attributes in terms of dog selection?

thank you.

Last edited by bonduie (2011-06-04 15:47:59)

Re: How to find the 3 closest matches in a search using ranked terms

Another way to ask this is to ask for the records with the smallest difference from the required values.  You can get the difference (in sql) with abs(val1 - val2).  So, get the difference for each field, add them together as a new virtual column and order by that.

params = {:speed => 6, :size => 8, :friendly => 4}
@dogs = Dogs.find(:all, :select => ["*,(abs(speed - #{params[:speed]}) + abs(size - #{params[:size]}) + abs(friendly - #{params[:friendly]})) as score"], :order => "score")

If you want to add weighting, then it's a case of multiplying the results of abs() by the weighting value, eg


params = {:speed => 6, :size => 8, :friendly => 4, :size_weighting => 2}
@dogs = Dogs.find(:all, :select => ["*,(abs(speed - #{params[:speed]})*#{params[:speed_weighting] || 1} + abs(size - #{params[:size]})*#{params[:size_weighting] || 1} + abs(friendly - #{params[:friendly]})*#{params[:friendly_weighting] || 1}) as score"], :order => "score")
###########################################
#If i've helped you then please recommend me at Working With Rails:
#http://www.workingwithrails.com/person/ … i-williams