Search code examples
rubyalgorithmmongoidrankingrecommendation-engine

Algorithm for increasing and decreasing a float in a passive rating system


I'd like to implement a passive rating system, and though this seems like a standard problem, I've been unable to find any implemented solutions.

My use case is:

As a user, I didn't like a book and want a different book. (this decreases the book's rating) As a user, I finished reading the book and marked it finished. (this increases the book's rating)

In ruby pseudocode:

class Book
  include Mongoid::Document
  field :subject, type: String
  field :rating, type: Float
end

def request_replacement
  self.rating -= 0.01
  return Book.where(subject: self.subject).all.sample
end

@book.request_replacement

The rating influences the likelihood the book will be recommended to readers in the future.

I initialized each book's rating as 0.50. I naively figured each time a user requested a substitute, I'd decrease the book's rating (-0.01), and each time a user marked the book finished, I'd increase the book's rating (+0.01).

I am afraid, however, that a bunch of early negative reviews could push a book's rating so low it's never recommended, and that too many positive reviews would lead to excessive recommendation of the book.

Is there a conventional way to increase and decrease the value of the float to prevent such runaway effects (perhaps asymptotically approaching 1 and 0 respectively?)

Thanks for your time and insights!


Solution

  • If you need a kind of coefficient, that starts from some value and asymptotically approaches 1, you can use exponential function e-x in the following way:

    1 - k*exp(-mt)
    

    where t is time or count of book queries, m is "speed" of growth (the bigger is m, the faster whole coefficient reaches ~1), 1 - k is the value at t = 0.

    http://fooplot.com

    Here, k = 0.5 and m = 1/20