FEATURE: Allow categories to be prioritized/deprioritized in search. (#7209)

This commit is contained in:
Guo Xiang Tan 2019-03-25 10:59:55 +08:00 committed by GitHub
parent ce75e30bf5
commit ac661e856a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 129 additions and 5 deletions

View File

@ -69,7 +69,7 @@ export default buildCategoryPanel("settings", {
});
}
return options.sort((a, b) => a.value <= b.value);
return options;
},
@computed

View File

@ -2,8 +2,12 @@ module Searchable
extend ActiveSupport::Concern
PRIORITIES = Enum.new(
ignore: 1,
very_low: 2,
low: 3,
normal: 0,
ignore: 1
high: 4,
very_high: 5
)
included do

View File

@ -2459,6 +2459,10 @@ en:
options:
normal: "Normal"
ignore: "Ignore"
very_low: "Very Low"
low: "Low"
high: "High"
very_high: "Very High"
sort_options:
default: "default"
likes: "Likes"

View File

@ -1291,6 +1291,10 @@ en:
search_query_log_max_size: "Maximum amount of search queries to keep"
search_query_log_max_retention_days: "Maximum amount of time to keep search queries, in days."
search_ignore_accents: "Ignore accents when searching for text."
category_search_priority_very_low_weight: "Weight applied to ranking for very low category search priority."
category_search_priority_low_weight: "Weight applied to ranking for low category search priority."
category_search_priority_high_weight: "Weight applied to ranking for high category search priority."
category_search_priority_very_high_weight: "Weight applied to ranking for very high category search priority."
allow_uncategorized_topics: "Allow topics to be created without a category. WARNING: If there are any uncategorized topics, you must recategorize them before turning this off."
allow_duplicate_topic_titles: "Allow topics with identical, duplicate titles."
unique_posts_mins: "How many minutes before a user can make a post with the same content again"
@ -2030,6 +2034,11 @@ en:
max_username_length_exists: "You cannot set the maximum username length below the longest username (%{username})."
max_username_length_range: "You cannot set the maximum below the minimum."
invalid_hex_value: "Color values have to be 6-digit hexadecimal codes."
category_search_priority:
very_low_weight_invalid: "You cannot set the weight to be greater than 'category_search_priority_low_weight'."
low_weight_invalid: "You cannot set the weight to be greater or equal to 1 or smaller than 'category_search_priority_very_low_weight'."
high_weight_invalid: "You cannot set the weight to be greater or equal to 1 or greater than 'category_search_priority_very_high_weight'."
very_high_weight_invalid: "You cannot set the weight to be smaller than 'category_search_priority_high_weight'."
placeholder:
sso_provider_secrets:

View File

@ -1614,6 +1614,22 @@ search:
ro: true
sk: true
tr_TR: true
category_search_priority_very_low_weight:
default: 0.6
hidden: true
validator: "CategorySearchPriorityWeightsValidator"
category_search_priority_low_weight:
default: 0.8
hidden: true
validator: "CategorySearchPriorityWeightsValidator"
category_search_priority_high_weight:
default: 1.2
hidden: true
validator: "CategorySearchPriorityWeightsValidator"
category_search_priority_very_high_weight:
default: 1.4
hidden: true
validator: "CategorySearchPriorityWeightsValidator"
uncategorized:
version_checks:

View File

@ -836,9 +836,27 @@ class Search
posts = posts.order("posts.like_count DESC")
end
else
# 0|32 default normalization scaled into the range zero to one
data_ranking = <<~SQL
TS_RANK_CD(
post_search_data.search_data, #{ts_query(weight_filter: weights)}
(
TS_RANK_CD(
post_search_data.search_data,
#{ts_query(weight_filter: weights)},
0|32
) *
(
CASE categories.search_priority
WHEN #{Searchable::PRIORITIES[:very_low]}
THEN #{SiteSetting.category_search_priority_very_low_weight}
WHEN #{Searchable::PRIORITIES[:low]}
THEN #{SiteSetting.category_search_priority_low_weight}
WHEN #{Searchable::PRIORITIES[:high]}
THEN #{SiteSetting.category_search_priority_high_weight}
WHEN #{Searchable::PRIORITIES[:very_high]}
THEN #{SiteSetting.category_search_priority_very_high_weight}
ELSE 1
END
)
)
SQL

View File

@ -103,7 +103,9 @@ class SiteSettings::TypeSupervisor
opts[:validator] = opts[:validator].try(:constantize)
if (validator_type = (opts[:validator] || validator_for(@types[name])))
@validators[name] = { class: validator_type, opts: opts.slice(*VALIDATOR_OPTS) }
validator_opts = opts.slice(*VALIDATOR_OPTS)
validator_opts[:name] = name
@validators[name] = { class: validator_type, opts: validator_opts }
end
end

View File

@ -0,0 +1,25 @@
class CategorySearchPriorityWeightsValidator
def initialize(opts = {})
@name = opts[:name].to_s
end
def valid_value?(val)
val = val.to_f
case @name
when "category_search_priority_very_low_weight"
val < SiteSetting.category_search_priority_low_weight
when "category_search_priority_low_weight"
val < 1 && val > SiteSetting.category_search_priority_very_low_weight
when "category_search_priority_high_weight"
val > 1 && val < SiteSetting.category_search_priority_very_high_weight
when "category_search_priority_very_high_weight"
val > SiteSetting.category_search_priority_high_weight
end
end
def error_message
key = @name[/category_search_priority_(\w+)_weight/, 1]
I18n.t("site_settings.errors.category_search_priority.#{key}_weight_invalid")
end
end

View File

@ -486,6 +486,26 @@ describe Search do
end
end
describe 'categories with different priorities' do
let(:category2) { Fabricate(:category) }
it "should return posts in the right order" do
raw = "The pure genuine evian"
post = Fabricate(:post, topic: category.topic, raw: raw)
post2 = Fabricate(:post, topic: category2.topic, raw: raw)
search = Search.execute(raw)
expect(search.posts).to eq([post2, post])
category.update!(search_priority: Searchable::PRIORITIES[:high])
search = Search.execute(raw)
expect(search.posts).to eq([post, post2])
end
end
end
context 'groups' do

View File

@ -0,0 +1,26 @@
require 'rails_helper'
require 'validators/category_search_priority_weights_validator'
RSpec.describe CategorySearchPriorityWeightsValidator do
it "should validate the results correctly" do
expect do
SiteSetting.category_search_priority_very_low_weight = 0.9
end.to raise_error(Discourse::InvalidParameters)
[1, 0].each do |value|
expect do
SiteSetting.category_search_priority_low_weight = value
end.to raise_error(Discourse::InvalidParameters)
end
['0.2', 10].each do |value|
expect do
SiteSetting.category_search_priority_high_weight = value
end.to raise_error(Discourse::InvalidParameters)
end
expect do
SiteSetting.category_search_priority_very_high_weight = 1.1
end.to raise_error(Discourse::InvalidParameters)
end
end