2013-02-06 03:16:51 +08:00
|
|
|
class ScoreCalculator
|
|
|
|
|
2013-02-26 00:42:20 +08:00
|
|
|
def self.default_score_weights
|
2013-02-06 03:16:51 +08:00
|
|
|
{
|
|
|
|
reply_count: 5,
|
2013-05-28 00:45:10 +08:00
|
|
|
like_score: 15,
|
2013-02-06 03:16:51 +08:00
|
|
|
incoming_link_count: 5,
|
|
|
|
bookmark_count: 2,
|
|
|
|
avg_time: 0.05,
|
|
|
|
reads: 0.2
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def initialize(weightings=nil)
|
|
|
|
@weightings = weightings || ScoreCalculator.default_score_weights
|
|
|
|
end
|
|
|
|
|
|
|
|
# Calculate the score for all posts based on the weightings
|
2014-02-27 08:45:20 +08:00
|
|
|
def calculate(min_topic_age=nil)
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2014-02-27 08:45:20 +08:00
|
|
|
update_posts_score(min_topic_age)
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2014-02-27 08:45:20 +08:00
|
|
|
update_posts_rank(min_topic_age)
|
|
|
|
|
|
|
|
update_topics_rank(min_topic_age)
|
|
|
|
|
|
|
|
update_topics_percent_rank(min_topic_age)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def update_posts_score(min_topic_age)
|
2016-07-08 10:54:03 +08:00
|
|
|
limit = 20000
|
|
|
|
|
2014-02-27 08:45:20 +08:00
|
|
|
components = []
|
2015-04-18 19:53:53 +08:00
|
|
|
@weightings.each_key { |k| components << "COALESCE(#{k}, 0) * :#{k}" }
|
2014-02-27 08:45:20 +08:00
|
|
|
components = components.join(" + ")
|
|
|
|
|
2016-07-08 10:54:03 +08:00
|
|
|
builder = SqlBuilder.new <<SQL
|
|
|
|
UPDATE posts p
|
|
|
|
SET score = x.score
|
|
|
|
FROM (
|
|
|
|
SELECT id, #{components} as score FROM posts
|
|
|
|
/*where*/
|
|
|
|
limit #{limit}
|
|
|
|
) AS x
|
|
|
|
WHERE x.id = p.id
|
|
|
|
SQL
|
2014-02-27 08:45:20 +08:00
|
|
|
|
2016-07-08 10:54:03 +08:00
|
|
|
builder.where("score IS NULL OR score <> #{components}", @weightings)
|
2014-02-27 08:45:20 +08:00
|
|
|
|
|
|
|
filter_topics(builder, min_topic_age)
|
|
|
|
|
2016-07-08 10:54:03 +08:00
|
|
|
while builder.exec.cmd_tuples == limit
|
|
|
|
end
|
2014-02-27 08:45:20 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def update_posts_rank(min_topic_age)
|
2016-07-08 10:54:03 +08:00
|
|
|
limit = 20000
|
|
|
|
|
|
|
|
builder = SqlBuilder.new <<SQL
|
|
|
|
UPDATE posts
|
|
|
|
SET percent_rank = X.percent_rank
|
|
|
|
FROM (
|
|
|
|
SELECT posts.id, Y.percent_rank
|
|
|
|
FROM posts
|
|
|
|
JOIN (
|
|
|
|
SELECT id, percent_rank()
|
|
|
|
OVER (PARTITION BY topic_id ORDER BY SCORE DESC) as percent_rank
|
|
|
|
FROM posts
|
|
|
|
) Y ON Y.id = posts.id
|
|
|
|
/*where*/
|
|
|
|
LIMIT #{limit}
|
|
|
|
) AS X
|
|
|
|
WHERE posts.id = X.id
|
|
|
|
SQL
|
|
|
|
|
|
|
|
builder.where("posts.percent_rank IS NULL OR Y.percent_rank <> posts.percent_rank")
|
2013-03-23 03:43:57 +08:00
|
|
|
|
2014-02-27 08:45:20 +08:00
|
|
|
filter_topics(builder, min_topic_age)
|
|
|
|
|
2016-07-08 10:54:03 +08:00
|
|
|
while builder.exec.cmd_tuples == limit
|
|
|
|
end
|
|
|
|
|
2014-02-27 08:45:20 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def update_topics_rank(min_topic_age)
|
|
|
|
builder = SqlBuilder.new("UPDATE topics AS t
|
2013-11-19 01:48:26 +08:00
|
|
|
SET has_summary = (t.like_count >= :likes_required AND
|
2013-03-29 01:02:59 +08:00
|
|
|
t.posts_count >= :posts_required AND
|
2013-03-30 00:54:16 +08:00
|
|
|
x.max_score >= :score_required),
|
2013-03-29 01:02:59 +08:00
|
|
|
score = x.avg_score
|
|
|
|
FROM (SELECT p.topic_id,
|
2013-03-30 00:54:16 +08:00
|
|
|
MAX(p.score) AS max_score,
|
2013-03-29 01:02:59 +08:00
|
|
|
AVG(p.score) AS avg_score
|
|
|
|
FROM posts AS p
|
|
|
|
GROUP BY p.topic_id) AS x
|
2014-02-27 08:45:20 +08:00
|
|
|
/*where*/")
|
|
|
|
|
|
|
|
builder.where("x.topic_id = t.id AND
|
2013-09-30 14:59:16 +08:00
|
|
|
(
|
|
|
|
(t.score <> x.avg_score OR t.score IS NULL) OR
|
2013-11-19 01:48:26 +08:00
|
|
|
(t.has_summary IS NULL OR t.has_summary <> (
|
2013-09-30 14:59:16 +08:00
|
|
|
t.like_count >= :likes_required AND
|
|
|
|
t.posts_count >= :posts_required AND
|
|
|
|
x.max_score >= :score_required
|
|
|
|
))
|
|
|
|
)
|
|
|
|
",
|
2013-11-19 01:48:26 +08:00
|
|
|
likes_required: SiteSetting.summary_likes_required,
|
|
|
|
posts_required: SiteSetting.summary_posts_required,
|
2014-02-27 08:45:20 +08:00
|
|
|
score_required: SiteSetting.summary_score_threshold)
|
|
|
|
|
|
|
|
if min_topic_age
|
|
|
|
builder.where("t.bumped_at > :bumped_at ",
|
|
|
|
bumped_at: min_topic_age)
|
|
|
|
end
|
|
|
|
|
|
|
|
builder.exec
|
|
|
|
end
|
2013-02-26 00:42:20 +08:00
|
|
|
|
2014-02-27 08:45:20 +08:00
|
|
|
def update_topics_percent_rank(min_topic_age)
|
|
|
|
|
|
|
|
builder = SqlBuilder.new("UPDATE topics SET percent_rank = x.percent_rank
|
2013-03-29 01:02:59 +08:00
|
|
|
FROM (SELECT id, percent_rank()
|
|
|
|
OVER (ORDER BY SCORE DESC) as percent_rank
|
|
|
|
FROM topics) AS x
|
2014-02-27 08:45:20 +08:00
|
|
|
/*where*/")
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2014-02-27 08:45:20 +08:00
|
|
|
builder.where("x.id = topics.id AND (topics.percent_rank <> x.percent_rank OR topics.percent_rank IS NULL)")
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
|
2014-02-27 08:45:20 +08:00
|
|
|
if min_topic_age
|
|
|
|
builder.where("topics.bumped_at > :bumped_at ",
|
|
|
|
bumped_at: min_topic_age)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2013-10-01 23:11:13 +08:00
|
|
|
|
2014-02-27 08:45:20 +08:00
|
|
|
builder.exec
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def filter_topics(builder, min_topic_age)
|
|
|
|
if min_topic_age
|
|
|
|
builder.where('posts.topic_id IN
|
|
|
|
(SELECT id FROM topics WHERE bumped_at > :bumped_at)',
|
|
|
|
bumped_at: min_topic_age)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
2014-02-27 08:45:20 +08:00
|
|
|
|
|
|
|
builder
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|