Files
fizzy/app/models/search.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

52 lines
1.8 KiB
Ruby

class Search
attr_reader :user, :query
def self.table_name_prefix
"search_"
end
def initialize(user, query)
@user = user
@query = Query.wrap(query)
end
def results
if query.valid? && board_ids.any?
perform_search
else
Search::Result.none
end
end
private
def board_ids
@board_ids ||= user.board_ids
end
def perform_search
query_string = query.to_s
sanitized_query = Search::Result.connection.quote(query_string)
sanitized_raw_query = Search::Result.connection.quote(query.terms)
table_name = Searchable.search_index_table_name(user.account_id)
Search::Result.from(table_name)
.joins("INNER JOIN cards ON #{table_name}.card_id = cards.id")
.joins("INNER JOIN boards ON cards.board_id = boards.id")
.where("#{table_name}.board_id IN (?)", board_ids)
.where("MATCH(#{table_name}.content, #{table_name}.title) AGAINST(? IN BOOLEAN MODE)", query_string)
.select([
"#{table_name}.card_id as card_id",
"CASE WHEN #{table_name}.searchable_type = 'Comment' THEN #{table_name}.searchable_id ELSE NULL END as comment_id",
"COALESCE(#{table_name}.title, cards.title) AS card_title_in_database",
"CASE WHEN #{table_name}.searchable_type = 'Card' THEN #{table_name}.content ELSE NULL END AS card_description_in_database",
"CASE WHEN #{table_name}.searchable_type = 'Comment' THEN #{table_name}.content ELSE NULL END AS comment_body_in_database",
"boards.name as board_name",
"cards.creator_id",
"#{table_name}.created_at as created_at",
"MATCH(#{table_name}.content, #{table_name}.title) AGAINST(#{sanitized_query} IN BOOLEAN MODE) AS score",
"#{sanitized_raw_query} AS query"
].join(","))
.order("#{table_name}.created_at DESC")
end
end