Files
fizzy/app/models/concerns/searchable.rb
T
Donal McBreen 3aa4a1a562 Shard the search index into 16 tables
Create search_index_0 to search_index_15 tables and shard each index by
account id. MySQL has no ability to pre-filter fulltext indexes by
another field so this is the best bet for improving performance.

Each fulltest index internally creates 11 sub tables (see
https://dev.mysql.com/doc/refman/8.4/en/innodb-fulltext-index.html) so
actually we have 192 tables in total here.

The search_index table name is generated dynamically based on the
account_id.
2025-11-17 09:12:17 -05:00

67 lines
1.9 KiB
Ruby

module Searchable
extend ActiveSupport::Concern
def self.search_index_table_name(account_id)
"search_index_#{account_id % 16}"
end
included do
after_create_commit :create_in_search_index
after_update_commit :update_in_search_index
after_destroy_commit :remove_from_search_index
end
def reindex
update_in_search_index
end
private
def create_in_search_index
table_name = Searchable.search_index_table_name(account_id)
self.class.connection.execute self.class.sanitize_sql([
"INSERT INTO #{table_name} (searchable_type, searchable_id, card_id, board_id, title, content, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
self.class.name,
id,
search_card_id,
search_board_id,
search_title,
search_content,
created_at
])
end
def update_in_search_index
table_name = Searchable.search_index_table_name(account_id)
result = self.class.connection.execute(self.class.sanitize_sql([
"UPDATE #{table_name} SET card_id = ?, board_id = ?, title = ?, content = ?, created_at = ? WHERE searchable_type = ? AND searchable_id = ?",
search_card_id,
search_board_id,
search_title,
search_content,
created_at,
self.class.name,
id
]))
create_in_search_index if result.affected_rows == 0
end
def remove_from_search_index
table_name = Searchable.search_index_table_name(account_id)
self.class.connection.execute self.class.sanitize_sql([
"DELETE FROM #{table_name} WHERE searchable_type = ? AND searchable_id = ?",
self.class.name,
id
])
end
# Models must implement these methods:
# - search_title: returns title string or nil
# - search_content: returns content string
# - search_card_id: returns the card id (self.id for cards, card_id for comments)
# - search_board_id: returns the board id
end