开发者

Find condition needs refactoring/optimising on polymorphic association

开发者 https://www.devze.com 2023-02-21 22:02 出处:网络
I\'m building a recommendation method for users in my project. Users generate interest records whenever they view, create, comment or interact with objects (weighted depending on the action).

I'm building a recommendation method for users in my project. Users generate interest records whenever they view, create, comment or interact with objects (weighted depending on the action).

I've written a find method that looks at a user's interests, and then finds users who are also interested in those items. However, it is horrendously inefficient, making as many db calls as the user has interests (up to 50).

Here's a chopped down version of what's going on:

#User.rb
...
has_many :interests, :as => :interestable, :dependent => :destroy

def recommendations
  recommendations = []

  Interest.for(self).limit(50).each do |item|
    recommendations << Interest.other_fans_of(item)
  end

  user_ids = recommendations.flatten.map(&:user_id).uniq
end
...

#interest.rb

...

belongs_to :user
belongs_to :interestable, :polymorphic => true

named_scope :for, lambda { |user| { :conditions => { :user_id => user.id } } }
named_scope :limit, lambda { |num| { :limit => num } }
named_scope :other_fans_of, lambda { |interest| { :conditions => { :interestable_t开发者_如何学Cype => interest.interestable_type, :interestable_id => interest.interestable_id } } }
default_scope :order => "weight DESC"

...

Are there any sql geniuses out there who can turn that into one nice clean db call?


Something like this should do the job. There might be prettier ways…

class User < ActiveRecord::Base
  #...
  def recommendations
    # get a list of the relevant interests
    the_interests = Interest.for(self).limit(50).map{|x| [x.interestable_type, x.interestable_id]}
    # make some sql
    conditions = the_interests.map{|x| "(`interestable_type`=? AND `interestable_id`=?)"}.join(" OR ")
    # use ruby magic to make a valid finder and get the other user_ids
    user_ids = Interest.all(:select => '`user_id`', :conditions => [conditions, *(the_interests.flatten)]).map(&:user_id).uniq
  end
  #...
end
0

精彩评论

暂无评论...
验证码 换一张
取 消