PERF: Switch to ActiveRecord's upsert in `SearchIndexer`.

PERF: Switch to ActiveRecord’s upsert in SearchIndexer.

On insertion, it uses a single query instead of 2.

diff --git a/app/services/search_indexer.rb b/app/services/search_indexer.rb
index bc9c7ec..4c0ac81 100644
--- a/app/services/search_indexer.rb
+++ b/app/services/search_indexer.rb
@@ -76,36 +76,22 @@ class SearchIndexer
       end
 
     params = {
-      raw_data: indexed_data,
-      id: id,
-      locale: SiteSetting.default_locale,
-      version: const_get("#{table.upcase}_INDEX_VERSION"),
-      tsvector: tsvector,
+      "raw_data" => indexed_data,
+      "#{foreign_key}" => id,
+      "locale" => SiteSetting.default_locale,
+      "version" => const_get("#{table.upcase}_INDEX_VERSION"),
+      "search_data" => tsvector,
     }
 
-    # Would be nice to use AR here but not sure how to execut Postgres functions
-    # when inserting data like this.
-    rows = DB.exec(<<~SQL, params)
-       UPDATE #{table_name}
-       SET
-          raw_data = :raw_data,
-          locale = :locale,
-          search_data = (:tsvector)::tsvector,
-          version = :version
-       WHERE #{foreign_key} = :id
-    SQL
-
-    if rows == 0
-      DB.exec(<<~SQL, params)
-        INSERT INTO #{table_name}
-        (#{foreign_key}, search_data, locale, raw_data, version)
-        VALUES (:id, (:tsvector)::tsvector, :locale, :raw_data, :version)
-      SQL
-    end
-  rescue
+    table_name.camelize.constantize.upsert(params)
+  rescue => e
     # TODO is there any way we can safely avoid this?
     # best way is probably pushing search indexer into a dedicated process so it no longer happens on save
     # instead in the post processor
+    Discourse.warn_exception(
+      e,
+      message: "Unexpected error while indexing #{table} for search"
+    )
   end
 
   def self.update_topics_index(topic_id, title, cooked)

GitHub sha: 5819c4cb

2 Likes