FIX: Reindex posts when `Topic#title` or `Category#name` changes.

This commit is contained in:
Guo Xiang Tan 2020-07-17 11:12:31 +08:00
parent 39fef99c37
commit ff7678e210
No known key found for this signature in database
GPG Key ID: FBD110179AAC1F20
4 changed files with 71 additions and 27 deletions

View File

@ -764,6 +764,10 @@ class Category < ActiveRecord::Base
end end
def index_search def index_search
if saved_change_to_attribute?(:name)
SearchIndexer.queue_category_posts_reindex(self.id)
end
SearchIndexer.index(self) SearchIndexer.index(self)
end end

View File

@ -338,8 +338,7 @@ class Topic < ActiveRecord::Base
ApplicationController.banner_json_cache.clear ApplicationController.banner_json_cache.clear
end end
if tags_changed || saved_change_to_attribute?(:category_id) if tags_changed || saved_change_to_attribute?(:category_id) || saved_change_to_attribute?(:title)
SearchIndexer.queue_post_reindex(self.id) SearchIndexer.queue_post_reindex(self.id)
if tags_changed if tags_changed

View File

@ -104,8 +104,8 @@ class SearchIndexer
update_index(table: 'topic', id: topic_id, raw_data: [title, scrubbed_cooked]) update_index(table: 'topic', id: topic_id, raw_data: [title, scrubbed_cooked])
end end
def self.update_posts_index(post_id, title, category, tags, cooked) def self.update_posts_index(post_id, topic_title, category_name, topic_tags, cooked)
update_index(table: 'post', id: post_id, raw_data: [title, category, tags, scrub_html_for_search(cooked)]) update_index(table: 'post', id: post_id, raw_data: [topic_title, category_name, topic_tags, scrub_html_for_search(cooked)])
end end
def self.update_users_index(user_id, username, name) def self.update_users_index(user_id, username, name)
@ -120,6 +120,20 @@ class SearchIndexer
update_index(table: 'tag', id: tag_id, raw_data: [name.downcase]) update_index(table: 'tag', id: tag_id, raw_data: [name.downcase])
end end
def self.queue_category_posts_reindex(category_id)
return if @disabled
DB.exec(<<~SQL, category_id: category_id, version: REINDEX_VERSION)
UPDATE post_search_data
SET version = :version
FROM posts
INNER JOIN topics ON posts.topic_id = topics.id
INNER JOIN categories ON topics.category_id = categories.id
WHERE post_search_data.post_id = posts.id
AND categories.id = :category_id
SQL
end
def self.queue_post_reindex(topic_id) def self.queue_post_reindex(topic_id)
return if @disabled return if @disabled

View File

@ -10,30 +10,48 @@ describe Search do
SearchIndexer.enable SearchIndexer.enable
end end
context 'post indexing observer' do context 'post indexing' do
before do fab!(:category) { Fabricate(:category_with_definition, name: 'america') }
@category = Fabricate(:category_with_definition, name: 'america') fab!(:topic) { Fabricate(:topic, title: 'sam saffron test topic', category: category) }
@topic = Fabricate(:topic, title: 'sam saffron test topic', category: @category) let!(:post) { Fabricate(:post, topic: topic, raw: 'this <b>fun test</b> <img src="bla" title="my image">') }
@post = Fabricate(:post, topic: @topic, raw: 'this <b>fun test</b> <img src="bla" title="my image">') let!(:post2) { Fabricate(:post, topic: topic) }
@indexed = @post.post_search_data.search_data
end
it "should index correctly" do it "should index correctly" do
expect(@indexed).to match(/fun/) search_data = post.post_search_data.search_data
expect(@indexed).to match(/sam/)
expect(@indexed).to match(/america/)
@topic.title = "harpi is the new title" expect(search_data).to match(/fun/)
@topic.save! expect(search_data).to match(/sam/)
@post.post_search_data.reload expect(search_data).to match(/america/)
@indexed = @post.post_search_data.search_data expect do
topic.update!(title: "harpi is the new title")
end.to change { post2.reload.post_search_data.version }.from(SearchIndexer::INDEX_VERSION).to(SearchIndexer::REINDEX_VERSION)
expect(@indexed).to match(/harpi/) expect(post.post_search_data.reload.search_data).to match(/harpi/)
end
it 'should update posts index when topic category changes' do
expect do
topic.update!(category: Fabricate(:category))
end.to change { post.reload.post_search_data.version }.from(SearchIndexer::INDEX_VERSION).to(SearchIndexer::REINDEX_VERSION)
.and change { post2.reload.post_search_data.version }.from(SearchIndexer::INDEX_VERSION).to(SearchIndexer::REINDEX_VERSION)
end
it 'should update posts index when topic tags changes' do
SiteSetting.tagging_enabled = true
tag = Fabricate(:tag)
expect do
DiscourseTagging.tag_topic_by_names(topic, Guardian.new(admin), [tag.name])
topic.save!
end.to change { post.reload.post_search_data.version }.from(SearchIndexer::INDEX_VERSION).to(SearchIndexer::REINDEX_VERSION)
.and change { post2.reload.post_search_data.version }.from(SearchIndexer::INDEX_VERSION).to(SearchIndexer::REINDEX_VERSION)
expect(topic.tags).to eq([tag])
end end
end end
context 'user indexing observer' do context 'user indexing' do
before do before do
@user = Fabricate(:user, username: 'fred', name: 'bob jones') @user = Fabricate(:user, username: 'fred', name: 'bob jones')
@indexed = @user.user_search_data.search_data @indexed = @user.user_search_data.search_data
@ -45,16 +63,25 @@ describe Search do
end end
end end
context 'category indexing observer' do context 'category indexing' do
before do let!(:category) { Fabricate(:category_with_definition, name: 'america') }
@category = Fabricate(:category_with_definition, name: 'america') let!(:topic) { Fabricate(:topic, category: category) }
@indexed = @category.category_search_data.search_data let!(:post) { Fabricate(:post, topic: topic) }
let!(:post2) { Fabricate(:post, topic: topic) }
let!(:post3) { Fabricate(:post) }
it "should index correctly" do
expect(category.category_search_data.search_data).to match(/america/)
end end
it "should pick up on name" do it 'should update posts index when category name changes' do
expect(@indexed).to match(/america/) expect do
end category.update!(name: 'some new name')
end.to change { post.reload.post_search_data.version }.from(SearchIndexer::INDEX_VERSION).to(SearchIndexer::REINDEX_VERSION)
.and change { post2.reload.post_search_data.version }.from(SearchIndexer::INDEX_VERSION).to(SearchIndexer::REINDEX_VERSION)
expect(post3.post_search_data.version).to eq(SearchIndexer::INDEX_VERSION)
end
end end
it 'strips zero-width characters from search terms' do it 'strips zero-width characters from search terms' do