# frozen_string_literal: true module Jobs class ReindexSearch < ::Jobs::Scheduled every 2.hours def execute(args) @verbose = args[:verbose] @cleanup_grace_period = 1.day.ago rebuild_categories rebuild_tags rebuild_topics rebuild_posts rebuild_users clean_topics clean_posts end def rebuild_categories(limit: 500, indexer: SearchIndexer) category_ids = load_problem_category_ids(limit) puts "rebuilding #{category_ids.size} categories" if @verbose category_ids.each do |id| category = Category.find_by(id: id) indexer.index(category, force: true) if category end end def rebuild_tags(limit: 1_000, indexer: SearchIndexer) tag_ids = load_problem_tag_ids(limit) puts "rebuilding #{tag_ids.size} tags" if @verbose tag_ids.each do |id| tag = Tag.find_by(id: id) indexer.index(tag, force: true) if tag end end def rebuild_topics(limit: 10_000, indexer: SearchIndexer) topic_ids = load_problem_topic_ids(limit) puts "rebuilding #{topic_ids.size} topics" if @verbose topic_ids.each do |id| topic = Topic.find_by(id: id) indexer.index(topic, force: true) if topic end end def rebuild_posts(limit: 20_000, indexer: SearchIndexer) post_ids = load_problem_post_ids(limit) puts "rebuilding #{post_ids.size} posts" if @verbose post_ids.each do |id| post = Post.find_by(id: id) indexer.index(post, force: true) if post end end def rebuild_users(limit: 5_000, indexer: SearchIndexer) user_ids = load_problem_user_ids(limit) puts "rebuilding #{user_ids.size} users" if @verbose user_ids.each do |id| user = User.find_by(id: id) indexer.index(user, force: true) if user end end def clean_topics puts "cleaning up topic search data" if @verbose # remove search data from deleted topics DB.exec(<<~SQL, deleted_at: @cleanup_grace_period) DELETE FROM topic_search_data WHERE topic_id IN ( SELECT topic_id FROM topic_search_data LEFT JOIN topics ON topic_id = topics.id WHERE topics.id IS NULL OR (deleted_at IS NOT NULL AND deleted_at <= :deleted_at) ) SQL end def clean_posts puts "cleaning up post search data" if @verbose # remove search data from deleted/empty posts DB.exec(<<~SQL, deleted_at: @cleanup_grace_period) DELETE FROM post_search_data WHERE post_id IN ( SELECT post_id FROM post_search_data LEFT JOIN posts ON post_id = posts.id JOIN topics ON posts.topic_id = topics.id WHERE posts.id IS NULL OR posts.raw = '' OR (posts.deleted_at IS NOT NULL AND posts.deleted_at <= :deleted_at) OR (topics.deleted_at IS NOT NULL AND topics.deleted_at <= :deleted_at) ) SQL end def load_problem_category_ids(limit) Category .joins("LEFT JOIN category_search_data ON category_id = categories.id") .where("category_search_data.locale IS NULL OR category_search_data.locale != ? OR category_search_data.version != ?", SiteSetting.default_locale, SearchIndexer::CATEGORY_INDEX_VERSION) .order("categories.id ASC") .limit(limit) .pluck(:id) end def load_problem_tag_ids(limit) Tag .joins("LEFT JOIN tag_search_data ON tag_id = tags.id") .where("tag_search_data.locale IS NULL OR tag_search_data.locale != ? OR tag_search_data.version != ?", SiteSetting.default_locale, SearchIndexer::TAG_INDEX_VERSION) .order("tags.id ASC") .limit(limit) .pluck(:id) end def load_problem_topic_ids(limit) Topic .joins("LEFT JOIN topic_search_data ON topic_id = topics.id") .where("topic_search_data.locale IS NULL OR topic_search_data.locale != ? OR topic_search_data.version != ?", SiteSetting.default_locale, SearchIndexer::TOPIC_INDEX_VERSION) .order("topics.id DESC") .limit(limit) .pluck(:id) end def load_problem_post_ids(limit) Post .joins(:topic) .joins("LEFT JOIN post_search_data ON post_id = posts.id") .where("posts.raw != ''") .where("topics.deleted_at IS NULL") .where("post_search_data.locale IS NULL OR post_search_data.locale != ? OR post_search_data.version != ?", SiteSetting.default_locale, SearchIndexer::POST_INDEX_VERSION) .order("posts.id DESC") .limit(limit) .pluck(:id) end def load_problem_user_ids(limit) User .joins("LEFT JOIN user_search_data ON user_id = users.id") .where("user_search_data.locale IS NULL OR user_search_data.locale != ? OR user_search_data.version != ?", SiteSetting.default_locale, SearchIndexer::USER_INDEX_VERSION) .order("users.id ASC") .limit(limit) .pluck(:id) end end end