3aa4a1a562
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.
52 lines
1.8 KiB
Ruby
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
|