FIX: Select earliest post when aggregating posts in a topic for search.
This is a revert ofd8c796bc44
and5bf0a0893b
. Linking to the post within a topic that has the highest rank was confusing users and hard to explain because ranking is determined via the PG ranking function. See the following meta topics for the complaints after we switch to the new ordering: 1. https://meta.discourse.org/t/title-search-not-working-as-expected/157737 2. https://meta.discourse.org/t/search-results-should-prioritize-first-post-in-topic-when-title-matches-search-term/175154
This commit is contained in:
parent
91fb298510
commit
4b3f65bb26
108
lib/search.rb
108
lib/search.rb
|
@ -986,53 +986,30 @@ class Search
|
|||
posts
|
||||
end
|
||||
|
||||
if aggregate_search
|
||||
aggregate_relation = Post.unscoped
|
||||
.select("subquery.topic_id id")
|
||||
.group("subquery.topic_id")
|
||||
|
||||
posts = posts.select(posts.arel.projections)
|
||||
end
|
||||
|
||||
if @order == :latest
|
||||
posts = posts.reorder("posts.created_at DESC")
|
||||
|
||||
if aggregate_search
|
||||
aggregate_relation = aggregate_relation
|
||||
.select(
|
||||
"MAX(subquery.post_number) post_number",
|
||||
"MAX(subquery.created_at) created_at"
|
||||
)
|
||||
.order("created_at DESC")
|
||||
posts = posts.order("MAX(posts.created_at) DESC")
|
||||
else
|
||||
posts = posts.reorder("posts.created_at DESC")
|
||||
end
|
||||
elsif @order == :latest_topic
|
||||
posts = posts.order("topics.created_at DESC")
|
||||
|
||||
if aggregate_search
|
||||
posts = posts.select("topics.created_at topic_created_at")
|
||||
|
||||
aggregate_relation = aggregate_relation
|
||||
.select(
|
||||
"MIN(subquery.post_number) post_number",
|
||||
"MAX(subquery.topic_created_at) topic_created_at"
|
||||
)
|
||||
.order("topic_created_at DESC")
|
||||
posts = posts.order("MAX(topics.created_at) DESC")
|
||||
else
|
||||
posts = posts.order("topics.created_at DESC")
|
||||
end
|
||||
elsif @order == :views
|
||||
posts = posts.order("topics.views DESC")
|
||||
|
||||
if aggregate_search
|
||||
posts = posts.select("topics.views topic_views")
|
||||
|
||||
aggregate_relation = aggregate_relation
|
||||
.select(
|
||||
"MIN(subquery.post_number) post_number",
|
||||
"MAX(subquery.topic_views) topic_views"
|
||||
)
|
||||
.order("topic_views DESC")
|
||||
posts = posts.order("MAX(topics.views) DESC")
|
||||
else
|
||||
posts = posts.order("topics.views DESC")
|
||||
end
|
||||
elsif @order == :likes
|
||||
if aggregate_search
|
||||
posts = posts.order("MAX(posts.like_count) DESC")
|
||||
else
|
||||
posts = posts.order("posts.like_count DESC")
|
||||
end
|
||||
else
|
||||
rank = <<~SQL
|
||||
TS_RANK_CD(
|
||||
|
@ -1069,30 +1046,21 @@ class Search
|
|||
"(#{rank} * #{category_priority_weights})"
|
||||
end
|
||||
|
||||
posts =
|
||||
if aggregate_search
|
||||
posts = posts.select("#{data_ranking} rank", "topics.bumped_at topic_bumped_at")
|
||||
.order("rank DESC", "topic_bumped_at DESC")
|
||||
|
||||
aggregate_relation = aggregate_relation
|
||||
.select(
|
||||
"(ARRAY_AGG(subquery.post_number ORDER BY subquery.rank DESC, subquery.topic_bumped_at DESC))[1] post_number",
|
||||
"MAX(subquery.rank) rank", "MAX(subquery.topic_bumped_at) topic_bumped_at"
|
||||
)
|
||||
.order("rank DESC", "topic_bumped_at DESC")
|
||||
posts.order("MAX(#{data_ranking}) DESC")
|
||||
else
|
||||
posts = posts.order("#{data_ranking} DESC", "topics.bumped_at DESC")
|
||||
end
|
||||
posts.order("#{data_ranking} DESC")
|
||||
end
|
||||
|
||||
posts = posts.order("topics.bumped_at DESC")
|
||||
end
|
||||
|
||||
posts =
|
||||
if secure_category_ids.present?
|
||||
posts = posts.where("(categories.id IS NULL) OR (NOT categories.read_restricted) OR (categories.id IN (?))", secure_category_ids).references(:categories)
|
||||
posts.where("(categories.id IS NULL) OR (NOT categories.read_restricted) OR (categories.id IN (?))", secure_category_ids).references(:categories)
|
||||
else
|
||||
posts = posts.where("(categories.id IS NULL) OR (NOT categories.read_restricted)").references(:categories)
|
||||
end
|
||||
|
||||
if aggregate_search
|
||||
posts = yield(posts) if block_given?
|
||||
posts = aggregate_relation.from(posts)
|
||||
posts.where("(categories.id IS NULL) OR (NOT categories.read_restricted)").references(:categories)
|
||||
end
|
||||
|
||||
if @order
|
||||
|
@ -1169,37 +1137,29 @@ class Search
|
|||
Search.min_post_id
|
||||
end
|
||||
|
||||
min_or_max = @order == :latest ? "max" : "min"
|
||||
|
||||
query =
|
||||
if @order == :likes
|
||||
# likes are a pain to aggregate so skip
|
||||
query = posts_query(limit, **default_opts).select('topics.id', 'posts.post_number')
|
||||
posts_query(limit, type_filter: opts[:type_filter])
|
||||
.select('topics.id', "posts.post_number")
|
||||
else
|
||||
posts_query(limit, aggregate_search: true, type_filter: opts[:type_filter])
|
||||
.select('topics.id', "#{min_or_max}(posts.post_number) post_number")
|
||||
.group('topics.id')
|
||||
end
|
||||
|
||||
if min_id > 0
|
||||
low_set = query.dup.where("post_search_data.post_id < #{min_id}")
|
||||
high_set = query.where("post_search_data.post_id >= #{min_id}")
|
||||
|
||||
{ default: wrap_rows(high_set), remaining: wrap_rows(low_set) }
|
||||
else
|
||||
{ default: wrap_rows(query) }
|
||||
end
|
||||
else
|
||||
query = posts_query(limit, **default_opts, aggregate_search: true) do |posts|
|
||||
if min_id > 0
|
||||
posts.select("post_search_data.post_id post_search_data_post_id")
|
||||
else
|
||||
posts
|
||||
end
|
||||
return { default: wrap_rows(high_set), remaining: wrap_rows(low_set) }
|
||||
end
|
||||
|
||||
if min_id > 0
|
||||
low_set = query.dup.where("subquery.post_search_data_post_id < #{min_id}")
|
||||
high_set = query.where("subquery.post_search_data_post_id >= #{min_id}")
|
||||
|
||||
{ default: wrap_rows(high_set), remaining: wrap_rows(low_set) }
|
||||
else
|
||||
# double wrapping so we get correct row numbers
|
||||
{ default: wrap_rows(query) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def aggregate_posts(post_sql)
|
||||
return [] unless post_sql
|
||||
|
|
|
@ -601,8 +601,8 @@ describe Search do
|
|||
expect(result.posts.pluck(:id)).to eq([post2.id, post.id])
|
||||
end
|
||||
|
||||
it 'aggregates searches in a topic by returning the post with the highest rank' do
|
||||
_post = Fabricate(:post, topic: topic, raw: "this is a play post")
|
||||
it 'aggregates searches in a topic by returning the post with the lowest post number' do
|
||||
post = Fabricate(:post, topic: topic, raw: "this is a play post")
|
||||
post2 = Fabricate(:post, topic: topic, raw: "play play playing played play")
|
||||
post3 = Fabricate(:post, raw: "this is a play post")
|
||||
|
||||
|
@ -613,7 +613,7 @@ describe Search do
|
|||
results = Search.execute('play')
|
||||
|
||||
expect(results.posts.map(&:id)).to eq([
|
||||
post2.id,
|
||||
post.id,
|
||||
post3.id
|
||||
])
|
||||
end
|
||||
|
@ -1892,9 +1892,11 @@ describe Search do
|
|||
|
||||
it 'allows to define custom order' do
|
||||
expect(Search.new("advanced").execute.posts).to eq([post1, post0])
|
||||
|
||||
Search.advanced_order(:chars) do |posts|
|
||||
posts.reorder("(SELECT LENGTH(raw) FROM posts WHERE posts.topic_id = subquery.topic_id) DESC")
|
||||
posts.reorder("MAX(LENGTH(posts.raw)) DESC")
|
||||
end
|
||||
|
||||
expect(Search.new("advanced order:chars").execute.posts).to eq([post0, post1])
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue