I suspect there is room for improvements with this, since it is really simplistic, and I certainly am not an expert in the subject. But it works ok for small numbers of items:
def Pair.from_items(items)
Pair.transaction do
res = []
all = items.reject { |i| i.name == "" }.collect { |i|
i.name.downcase }.sort
all.collect { |i| ([i]*all.length).zip(all) }.each { |i|
i.each {|j| res << j} }
res = res.each { |i| i.sort! }.uniq.reject { |p|
p[0] == p[1] }
res.each do |pair|
p = Pair.find(:first, :conditions =>
['val1 = ? and val2 = ?',
pair[0], pair[1]])
p ||= Pair.new(:val1 => pair[0], :val2 => pair[1],
:num => 0)
p.num += 1
p.save!
end
end
end
Basically what happens is that for a list of items [A, B, C, D], it calculates and inserts into the database that A and B have been purchased/rated/viewed/whatevered together once. Same for A and C, A and D, B and C, and so on. After accumulating enough of these pairs, you can query the datbase for an item – B for instance – and see what it’s been purchased with the most times, and recommend that to people who have shown an interest in B. When someone purchases a group of items togehter, you call Pair.from_items(the_items)
and it takes care of inserting the various combinations.