VRFS-3316 : Reduce method to roll up reviews

* Creates review_summaries
* Calculate and store wilson score
* Unit tests
This commit is contained in:
Steven Miers 2015-07-20 16:49:22 -05:00
parent 4b52d97a64
commit 2c594bf783
4 changed files with 72 additions and 10 deletions

View File

@ -10,11 +10,35 @@ module JamRuby
validates :target, presence:true
validates :user, presence:true
validates :target_id, uniqueness: {scope: :user_id, message: "There is already a review for this User and Target."}
# # @options - can contain values:
# # * target_id (optional)
# def reduce(options)
# arel = Review.where("deleted_at=?", nil)
# end
class << self
# Create review_summary records by grouping reviews
def reduce()
ReviewSummary.transaction do
ReviewSummary.destroy_all
Review.select("target_id, target_type AS target_type, AVG(rating) as avg_rating, count(*) as review_count, SUM(CASE WHEN rating>=3.0 THEN 1 ELSE 0 END) AS pos_count").group("target_type, target_id")
.each do |r|
#puts "Reducing reviews: #{r.inspect} #{r.pos_count} / #{r.review_count}"
ReviewSummary.create!(
target_id: r.target_id,
target_type: r.target_type,
avg_rating: r.avg_rating,
wilson_score: ci_lower_bound(r.pos_count, r.review_count),
review_count: r.review_count
)
end # each
end # transaction
end # reduce
def ci_lower_bound(pos, n, confidence=0.95)
pos=pos.to_f
n=n.to_f
return 0 if n == 0
z = 1.96 # Statistics2.pnormaldist(1-(1-confidence)/2)
phat = 1.0*pos/n
(phat + z*z/(2*n) - z * Math.sqrt((phat*(1-phat)+z*z/(4*n))/n))/(1+z*z/n)
end
end # self
end
end

View File

@ -1,12 +1,13 @@
module JamRuby
class ReviewSummary < ActiveRecord::Base
attr_accessible :target, :target_type, :avg_rating, :wilson_score, :review_count
attr_accessible :target, :target_id, :target_type, :avg_rating, :wilson_score, :review_count
belongs_to :target, polymorphic: true
validates :avg_rating, presence:true, numericality: true
validates :review_count, presence:true, numericality: {only_integer: true}
validates :wilson_score, presence:true, numericality: {greater_than:0, less_than:1}
validates :target, presence:true
validates :target_id, uniqueness:true
validates :target_id, presence:true, uniqueness:true
end
end

View File

@ -139,6 +139,17 @@ FactoryGirl.define do
end
end
factory :review, :class => JamRuby::Review do
sequence(:name) { |n| "Band" }
biography "My Biography"
city "Apex"
state "NC"
country "US"
before(:create) { |review|
review.genres << Genre.first
}
end
factory :music_session, :class => JamRuby::MusicSession do
sequence(:name) { |n| "Music Session #{n}" }
sequence(:description) { |n| "Music Session Description #{n}" }

View File

@ -46,8 +46,33 @@ describe Review do
review2 = Review.create(target:target, rating:3, user:@user)
review2.valid?.should be_false
end
end
it "reduces" do
review = Review.create(target:target, rating:3, user:@user)
review.valid?.should be_true
review2 = Review.create(target:target, rating:5, user:FactoryGirl.create(:user))
review2.valid?.should be_true
Review.count.should eq(2)
ReviewSummary.count.should eq(0)
Review.reduce()
ReviewSummary.count.should eq(1)
ReviewSummary.first.avg_rating.should eq(4.0)
puts "ORIG: #{ReviewSummary.all.inspect}"
ws_orig = ReviewSummary.first.wilson_score
avg_orig = ReviewSummary.first.avg_rating
5.times {Review.create(target:target, rating:5, user:FactoryGirl.create(:user))}
Review.reduce()
ReviewSummary.first.wilson_score.should > ws_orig
ReviewSummary.first.avg_rating.should > avg_orig
puts "ALL: #{ReviewSummary.all.inspect}"
end
end # context
context "validates review summary" do
it "blank target" do
review_summary = ReviewSummary.create()
@ -99,4 +124,5 @@ describe Review do
it_behaves_like :review, @jam_track, "jam_track"
end
end