Make account search blazing fast and rank followers/followees higher in the results
This commit is contained in:
		@ -2,7 +2,6 @@
 | 
			
		||||
 | 
			
		||||
class Account < ApplicationRecord
 | 
			
		||||
  include Targetable
 | 
			
		||||
  include PgSearch
 | 
			
		||||
 | 
			
		||||
  MENTION_RE = /(?:^|[^\/\w])@([a-z0-9_]+(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i
 | 
			
		||||
  IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze
 | 
			
		||||
@ -56,9 +55,6 @@ class Account < ApplicationRecord
 | 
			
		||||
  # PuSH subscriptions
 | 
			
		||||
  has_many :subscriptions, dependent: :destroy
 | 
			
		||||
 | 
			
		||||
  pg_search_scope :search_for, against: { display_name: 'A', username: 'B', domain: 'C' },
 | 
			
		||||
                               using: { tsearch: { prefix: true } }
 | 
			
		||||
 | 
			
		||||
  scope :remote, -> { where.not(domain: nil) }
 | 
			
		||||
  scope :local, -> { where(domain: nil) }
 | 
			
		||||
  scope :without_followers, -> { where('(select count(f.id) from follows as f where f.target_account_id = accounts.id) = 0') }
 | 
			
		||||
@ -212,6 +208,42 @@ SQL
 | 
			
		||||
      Account.find_by_sql([sql, account.id, account.id, limit])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def search_for(terms, limit = 10)
 | 
			
		||||
      textsearch  = '(setweight(to_tsvector(\'simple\', accounts.display_name), \'A\') || setweight(to_tsvector(\'simple\', accounts.username), \'B\') || setweight(to_tsvector(\'simple\', coalesce(accounts.domain, \'\')), \'C\'))'
 | 
			
		||||
      query       = 'to_tsquery(\'simple\', \'\'\' \' || ? || \' \'\'\' || \':*\')'
 | 
			
		||||
 | 
			
		||||
      sql = <<SQL
 | 
			
		||||
        SELECT
 | 
			
		||||
          accounts.*,
 | 
			
		||||
          ts_rank_cd(#{textsearch}, #{query}, 32) AS rank
 | 
			
		||||
        FROM accounts
 | 
			
		||||
        WHERE #{query} @@ #{textsearch}
 | 
			
		||||
        ORDER BY rank DESC
 | 
			
		||||
        LIMIT ?
 | 
			
		||||
SQL
 | 
			
		||||
 | 
			
		||||
      Account.find_by_sql([sql, terms, terms, limit])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def advanced_search_for(terms, account, limit = 10)
 | 
			
		||||
      textsearch  = '(setweight(to_tsvector(\'simple\', accounts.display_name), \'A\') || setweight(to_tsvector(\'simple\', accounts.username), \'B\') || setweight(to_tsvector(\'simple\', coalesce(accounts.domain, \'\')), \'C\'))'
 | 
			
		||||
      query       = 'to_tsquery(\'simple\', \'\'\' \' || ? || \' \'\'\' || \':*\')'
 | 
			
		||||
 | 
			
		||||
      sql = <<SQL
 | 
			
		||||
        SELECT
 | 
			
		||||
          accounts.*,
 | 
			
		||||
          (count(f.id) + 1) * ts_rank_cd(#{textsearch}, #{query}, 32) AS rank
 | 
			
		||||
        FROM accounts
 | 
			
		||||
        LEFT OUTER JOIN follows AS f ON (accounts.id = f.account_id AND f.target_account_id = ?) OR (accounts.id = f.target_account_id AND f.account_id = ?)
 | 
			
		||||
        WHERE #{query} @@ #{textsearch}
 | 
			
		||||
        GROUP BY accounts.id
 | 
			
		||||
        ORDER BY rank DESC
 | 
			
		||||
        LIMIT ?
 | 
			
		||||
SQL
 | 
			
		||||
 | 
			
		||||
      Account.find_by_sql([sql, terms, account.id, account.id, terms, limit])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def following_map(target_account_ids, account_id)
 | 
			
		||||
      follow_mapping(Follow.where(target_account_id: target_account_ids, account_id: account_id), :target_account_id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user