new algorithm for filter 'most active'

This commit is contained in:
Julian Herrero
2018-12-11 16:02:08 +01:00
parent 96dfa2fd65
commit ef835bef1c
9 changed files with 230 additions and 87 deletions

View File

@@ -122,14 +122,11 @@ class Debate < ActiveRecord::Base
end
def after_commented
save # updates the hot_score because there is a before_save
save # update cache when it has a new comment
end
def calculate_hot_score
self.hot_score = ScoreCalculator.hot_score(created_at,
cached_votes_total,
cached_votes_up,
comments_count)
self.hot_score = ScoreCalculator.hot_score(self)
end
def calculate_confidence_score

View File

@@ -121,14 +121,11 @@ class Legislation::Proposal < ActiveRecord::Base
end
def after_commented
save # updates the hot_score because there is a before_save
save # update cache when it has a new comment
end
def calculate_hot_score
self.hot_score = ScoreCalculator.hot_score(created_at,
total_votes,
total_votes,
comments_count)
self.hot_score = ScoreCalculator.hot_score(self)
end
def calculate_confidence_score

View File

@@ -166,14 +166,11 @@ class Proposal < ActiveRecord::Base
end
def after_commented
save # updates the hot_score because there is a before_save
save # update cache when it has a new comment
end
def calculate_hot_score
self.hot_score = ScoreCalculator.hot_score(created_at,
total_votes,
total_votes,
comments_count)
self.hot_score = ScoreCalculator.hot_score(self)
end
def calculate_confidence_score

View File

@@ -106,7 +106,7 @@ es:
orders:
confidence_score: Mejor valorados
created_at: Nuevos
hot_score: Más activos hoy
hot_score: Más activos
most_commented: Más comentados
relevance: Más relevantes
recommendations: Recomendaciones
@@ -346,7 +346,7 @@ es:
orders:
confidence_score: Más apoyadas
created_at: Nuevas
hot_score: Más activas hoy
hot_score: Más activas
most_commented: Más comentadas
relevance: Más relevantes
archival_date: Archivadas

View File

@@ -1,19 +1,19 @@
module ScoreCalculator
EPOC = Time.new(2015, 6, 15).in_time_zone
COMMENT_WEIGHT = 1.0 / 5 # 1 positive vote / x comments
TIME_UNIT = 24.hours.to_f
def self.hot_score(resource)
return 0 unless resource.created_at
def self.hot_score(date, votes_total, votes_up, comments_count)
total = (votes_total + COMMENT_WEIGHT * comments_count).to_f
ups = (votes_up + COMMENT_WEIGHT * comments_count).to_f
downs = total - ups
score = ups - downs
offset = Math.log([score.abs, 1].max, 10) * (ups / [total, 1].max)
sign = score <=> 0
seconds = ((date || Time.current) - EPOC).to_f
period = [
Setting['hot_score_period_in_days'].to_i,
((Time.current - resource.created_at) / 1.day).ceil
].min
(((offset * sign) + (seconds / TIME_UNIT)) * 10000000).round
votes_total = resource.votes_for.where("created_at >= ?", period.days.ago).count
votes_up = resource.get_upvotes.where("created_at >= ?", period.days.ago).count
votes_down = votes_total - votes_up
votes_score = votes_up - votes_down
(votes_score.to_f / period).round
end
def self.confidence_score(votes_total, votes_up)

View File

@@ -13,4 +13,15 @@ namespace :votes do
end
desc "Resets hot_score to its new value"
task reset_hot_score: :environment do
models = [Debate, Proposal, Legislation::Proposal]
models.each do |model|
model.find_each do |resource|
resource.save
print "."
end
end
end
end

View File

@@ -236,57 +236,91 @@ describe Debate do
describe '#hot_score' do
let(:now) { Time.current }
it "increases for newer debates" do
old = create(:debate, :with_hot_score, created_at: now - 1.day)
new = create(:debate, :with_hot_score, created_at: now)
expect(new.hot_score).to be > old.hot_score
it "period is correctly calculated to get exact votes per day" do
new_debate = create(:debate, created_at: 23.hours.ago)
2.times { new_debate.vote_by(voter: create(:user), vote: "yes") }
expect(new_debate.hot_score).to be 2
old_debate = create(:debate, created_at: 25.hours.ago)
2.times { old_debate.vote_by(voter: create(:user), vote: "yes") }
expect(old_debate.hot_score).to be 1
older_debate = create(:debate, created_at: 49.hours.ago)
3.times { older_debate.vote_by(voter: create(:user), vote: "yes") }
expect(old_debate.hot_score).to be 1
end
it "increases for debates with more comments" do
more_comments = create(:debate, :with_hot_score, created_at: now, comments_count: 25)
less_comments = create(:debate, :with_hot_score, created_at: now, comments_count: 1)
expect(more_comments.hot_score).to be > less_comments.hot_score
it "remains the same for not voted debates" do
new = create(:debate, created_at: now)
old = create(:debate, created_at: 1.day.ago)
older = create(:debate, created_at: 2.month.ago)
expect(new.hot_score).to be 0
expect(old.hot_score).to be 0
expect(older.hot_score).to be 0
end
it "increases for debates with more positive votes" do
more_likes = create(:debate, :with_hot_score, created_at: now, cached_votes_total: 10, cached_votes_up: 5)
less_likes = create(:debate, :with_hot_score, created_at: now, cached_votes_total: 10, cached_votes_up: 1)
expect(more_likes.hot_score).to be > less_likes.hot_score
more_positive_votes = create(:debate)
2.times { more_positive_votes.vote_by(voter: create(:user), vote: "yes") }
less_positive_votes = create(:debate)
less_positive_votes.vote_by(voter: create(:user), vote: "yes")
expect(more_positive_votes.hot_score).to be > less_positive_votes.hot_score
end
it "increases for debates with more confidence" do
more_confidence = create(:debate, :with_hot_score, created_at: now, cached_votes_total: 1000, cached_votes_up: 700)
less_confidence = create(:debate, :with_hot_score, created_at: now, cached_votes_total: 10, cached_votes_up: 9)
expect(more_confidence.hot_score).to be > less_confidence.hot_score
it "increases for debates with the same amount of positive votes within less days" do
newer_debate = create(:debate, created_at: now)
5.times { newer_debate.vote_by(voter: create(:user), vote: "yes") }
older_debate = create(:debate, created_at: 1.day.ago)
5.times { older_debate.vote_by(voter: create(:user), vote: "yes") }
expect(newer_debate.hot_score).to be > older_debate.hot_score
end
it "decays in older debates, even if they have more votes" do
older_more_voted = create(:debate, :with_hot_score, created_at: now - 5.days, cached_votes_total: 1000, cached_votes_up: 900)
new_less_voted = create(:debate, :with_hot_score, created_at: now, cached_votes_total: 10, cached_votes_up: 9)
expect(new_less_voted.hot_score).to be > older_more_voted.hot_score
it "decreases for debates with more negative votes" do
more_negative_votes = create(:debate)
5.times { more_negative_votes.vote_by(voter: create(:user), vote: "yes") }
3.times { more_negative_votes.vote_by(voter: create(:user), vote: "no") }
less_negative_votes = create(:debate)
5.times { less_negative_votes.vote_by(voter: create(:user), vote: "yes") }
2.times { less_negative_votes.vote_by(voter: create(:user), vote: "no") }
expect(more_negative_votes.hot_score).to be < less_negative_votes.hot_score
end
it "increases for debates voted within the period (last month by default)" do
newer_debate = create(:debate, created_at: 2.months.ago)
20.times { create(:vote, votable: newer_debate, created_at: 3.days.ago) }
older_debate = create(:debate, created_at: 2.months.ago)
20.times { create(:vote, votable: older_debate, created_at: 40.days.ago) }
expect(newer_debate.hot_score).to be > older_debate.hot_score
end
describe 'actions which affect it' do
let(:debate) { create(:debate, :with_hot_score) }
it "increases with likes" do
let(:debate) { create(:debate) }
before do
5.times { debate.vote_by(voter: create(:user), vote: "yes") }
2.times { debate.vote_by(voter: create(:user), vote: "no") }
end
it "increases with positive votes" do
previous = debate.hot_score
5.times { debate.register_vote(create(:user), true) }
3.times { debate.vote_by(voter: create(:user), vote: "yes") }
expect(previous).to be < debate.hot_score
end
it "decreases with dislikes" do
debate.register_vote(create(:user), true)
it "decreases with negative votes" do
previous = debate.hot_score
3.times { debate.register_vote(create(:user), false) }
3.times { debate.vote_by(voter: create(:user), vote: "no") }
expect(previous).to be > debate.hot_score
end
it "increases with comments" do
previous = debate.hot_score
25.times{ Comment.create(user: create(:user), commentable: debate, body: 'foobarbaz') }
expect(previous).to be < debate.reload.hot_score
end
end
end

View File

@@ -27,4 +27,82 @@ describe Legislation::Proposal do
expect(proposal).not_to be_valid
end
describe '#hot_score' do
let(:now) { Time.current }
it "period is correctly calculated to get exact votes per day" do
new_proposal = create(:legislation_proposal, created_at: 23.hours.ago)
2.times { new_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(new_proposal.hot_score).to be 2
old_proposal = create(:legislation_proposal, created_at: 25.hours.ago)
2.times { old_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(old_proposal.hot_score).to be 1
older_proposal = create(:legislation_proposal, created_at: 49.hours.ago)
3.times { older_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(old_proposal.hot_score).to be 1
end
it "remains the same for not voted proposals" do
new = create(:legislation_proposal, created_at: now)
old = create(:legislation_proposal, created_at: 1.day.ago)
older = create(:legislation_proposal, created_at: 2.month.ago)
expect(new.hot_score).to be 0
expect(old.hot_score).to be 0
expect(older.hot_score).to be 0
end
it "increases for proposals with more positive votes" do
more_positive_votes = create(:legislation_proposal)
2.times { more_positive_votes.vote_by(voter: create(:user), vote: "yes") }
less_positive_votes = create(:legislation_proposal)
less_positive_votes.vote_by(voter: create(:user), vote: "yes")
expect(more_positive_votes.hot_score).to be > less_positive_votes.hot_score
end
it "increases for proposals with the same amount of positive votes within less days" do
newer_proposal = create(:legislation_proposal, created_at: now)
5.times { newer_proposal.vote_by(voter: create(:user), vote: "yes") }
older_proposal = create(:legislation_proposal, created_at: 1.day.ago)
5.times { older_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(newer_proposal.hot_score).to be > older_proposal.hot_score
end
it "increases for proposals voted within the period (last month by default)" do
newer_proposal = create(:legislation_proposal, created_at: 2.months.ago)
20.times { create(:vote, votable: newer_proposal, created_at: 3.days.ago) }
older_proposal = create(:legislation_proposal, created_at: 2.months.ago)
20.times { create(:vote, votable: older_proposal, created_at: 40.days.ago) }
expect(newer_proposal.hot_score).to be > older_proposal.hot_score
end
describe 'actions which affect it' do
let(:proposal) { create(:legislation_proposal) }
before do
5.times { proposal.vote_by(voter: create(:user), vote: "yes") }
2.times { proposal.vote_by(voter: create(:user), vote: "no") }
end
it "increases with positive votes" do
previous = proposal.hot_score
3.times { proposal.vote_by(voter: create(:user), vote: "yes") }
expect(previous).to be < proposal.hot_score
end
it "decreases with negative votes" do
previous = proposal.hot_score
3.times { proposal.vote_by(voter: create(:user), vote: "no") }
expect(previous).to be > proposal.hot_score
end
end
end
end

View File

@@ -254,49 +254,78 @@ describe Proposal do
describe '#hot_score' do
let(:now) { Time.current }
it "increases for newer proposals" do
old = create(:proposal, :with_hot_score, created_at: now - 1.day)
new = create(:proposal, :with_hot_score, created_at: now)
expect(new.hot_score).to be > old.hot_score
it "period is correctly calculated to get exact votes per day" do
new_proposal = create(:proposal, created_at: 23.hours.ago)
2.times { new_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(new_proposal.hot_score).to be 2
old_proposal = create(:proposal, created_at: 25.hours.ago)
2.times { old_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(old_proposal.hot_score).to be 1
older_proposal = create(:proposal, created_at: 49.hours.ago)
3.times { older_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(old_proposal.hot_score).to be 1
end
it "increases for proposals with more comments" do
more_comments = create(:proposal, :with_hot_score, created_at: now, comments_count: 25)
less_comments = create(:proposal, :with_hot_score, created_at: now, comments_count: 1)
expect(more_comments.hot_score).to be > less_comments.hot_score
it "remains the same for not voted proposals" do
new = create(:proposal, created_at: now)
old = create(:proposal, created_at: 1.day.ago)
older = create(:proposal, created_at: 2.month.ago)
expect(new.hot_score).to be 0
expect(old.hot_score).to be 0
expect(older.hot_score).to be 0
end
it "increases for proposals with more positive votes" do
more_likes = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 5)
less_likes = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 1)
expect(more_likes.hot_score).to be > less_likes.hot_score
more_positive_votes = create(:proposal)
2.times { more_positive_votes.vote_by(voter: create(:user), vote: "yes") }
less_positive_votes = create(:proposal)
less_positive_votes.vote_by(voter: create(:user), vote: "yes")
expect(more_positive_votes.hot_score).to be > less_positive_votes.hot_score
end
it "increases for proposals with more confidence" do
more_confidence = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 700)
less_confidence = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 9)
expect(more_confidence.hot_score).to be > less_confidence.hot_score
it "increases for proposals with the same amount of positive votes within less days" do
newer_proposal = create(:proposal, created_at: now)
5.times { newer_proposal.vote_by(voter: create(:user), vote: "yes") }
older_proposal = create(:proposal, created_at: 1.day.ago)
5.times { older_proposal.vote_by(voter: create(:user), vote: "yes") }
expect(newer_proposal.hot_score).to be > older_proposal.hot_score
end
it "decays in older proposals, even if they have more votes" do
older_more_voted = create(:proposal, :with_hot_score, created_at: now - 5.days, cached_votes_up: 900)
new_less_voted = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 9)
expect(new_less_voted.hot_score).to be > older_more_voted.hot_score
it "increases for proposals voted within the period (last month by default)" do
newer_proposal = create(:proposal, created_at: 2.months.ago)
20.times { create(:vote, votable: newer_proposal, created_at: 3.days.ago) }
older_proposal = create(:proposal, created_at: 2.months.ago)
20.times { create(:vote, votable: older_proposal, created_at: 40.days.ago) }
expect(newer_proposal.hot_score).to be > older_proposal.hot_score
end
describe 'actions which affect it' do
let(:proposal) { create(:proposal, :with_hot_score) }
it "increases with votes" do
previous = proposal.hot_score
5.times { proposal.register_vote(create(:user, verified_at: Time.current), true) }
expect(previous).to be < proposal.reload.hot_score
let(:proposal) { create(:proposal) }
before do
5.times { proposal.vote_by(voter: create(:user), vote: "yes") }
2.times { proposal.vote_by(voter: create(:user), vote: "no") }
end
it "increases with comments" do
it "increases with positive votes" do
previous = proposal.hot_score
25.times{ Comment.create(user: create(:user), commentable: proposal, body: 'foobarbaz') }
expect(previous).to be < proposal.reload.hot_score
3.times { proposal.vote_by(voter: create(:user), vote: "yes") }
expect(previous).to be < proposal.hot_score
end
it "decreases with negative votes" do
previous = proposal.hot_score
3.times { proposal.vote_by(voter: create(:user), vote: "no") }
expect(previous).to be > proposal.hot_score
end
end
end