discourse/app/services/heat_settings_updater.rb
Neil Lalonde ecc9c76692
FEATURE: dynamically update the topic heat settings monthly (#7670)
The site settings beginning with "topic views heat" and "topic post like
heat" are set to defaults when installing Discourse, but there has not
been a process or guidance for updating these values based on
community activity.

This feature will update them once a month. The low, medium, and
high settings will be based on the minimums of the 45th, 25th, and
10th percentile topics respectively, so that 45% of topics will have
some "heat".

Disable automatic changes with the automatic_topic_heat_values setting.
2019-06-04 10:34:07 -04:00

82 lines
2.4 KiB
Ruby

# frozen_string_literal: true
class HeatSettingsUpdater
def self.update
return unless SiteSetting.automatic_topic_heat_values
views_by_percentile = views_thresholds
update_setting(:topic_views_heat_high, views_by_percentile[10])
update_setting(:topic_views_heat_medium, views_by_percentile[25])
update_setting(:topic_views_heat_low, views_by_percentile[45])
like_ratios_by_percentile = like_ratio_thresholds
update_setting(:topic_post_like_heat_high, like_ratios_by_percentile[10])
update_setting(:topic_post_like_heat_medium, like_ratios_by_percentile[25])
update_setting(:topic_post_like_heat_low, like_ratios_by_percentile[45])
end
def self.views_thresholds
results = DB.query(<<~SQL)
SELECT ranked.bucket * 5 as percentile, MIN(ranked.views) as views
FROM (
SELECT NTILE(20) OVER (ORDER BY t.views DESC) AS bucket, t.views
FROM (
SELECT views
FROM topics
WHERE deleted_at IS NULL
AND archetype <> 'private_message'
AND visible = TRUE
) t
) ranked
WHERE bucket <= 9
GROUP BY bucket
SQL
results.inject({}) do |h, row|
h[row.percentile] = row.views
h
end
end
def self.like_ratio_thresholds
results = DB.query(<<~SQL)
SELECT ranked.bucket * 5 as percentile, MIN(ranked.ratio) as like_ratio
FROM (
SELECT NTILE(20) OVER (ORDER BY t.ratio DESC) AS bucket, t.ratio
FROM (
SELECT like_count::decimal / posts_count AS ratio
FROM topics
WHERE deleted_at IS NULL
AND archetype <> 'private_message'
AND visible = TRUE
AND posts_count >= 10
AND like_count > 0
ORDER BY created_at DESC
LIMIT 1000
) t
) ranked
WHERE bucket <= 9
GROUP BY bucket
SQL
results.inject({}) do |h, row|
h[row.percentile] = row.like_ratio
h
end
end
def self.update_setting(name, new_value)
if new_value.nil? || new_value <= SiteSetting.defaults[name]
if SiteSetting.get(name) != SiteSetting.defaults[name]
SiteSetting.set_and_log(name, SiteSetting.defaults[name])
end
elsif SiteSetting.get(name) == 0 ||
(new_value.to_f / SiteSetting.get(name) - 1.0).abs >= 0.05
if SiteSetting.get(name) != new_value
SiteSetting.set_and_log(name, new_value)
end
end
end
end