Skip to content

Commit

Permalink
Add the followers option to AccountSearchSercive
Browse files Browse the repository at this point in the history
  • Loading branch information
noellabo committed Sep 5, 2020
1 parent 65e2b0c commit d7c3145
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 46 deletions.
1 change: 1 addition & 0 deletions app/controllers/api/v1/accounts/search_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def account_search
limit: limit_param(DEFAULT_ACCOUNTS_LIMIT),
resolve: truthy_param?(:resolve),
following: truthy_param?(:following),
followers: truthy_param?(:followers),
offset: params[:offset]
)
end
Expand Down
121 changes: 76 additions & 45 deletions app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -431,59 +431,52 @@ def search_for(terms, limit = 10, offset = 0)
AND accounts.suspended_at IS NULL
AND accounts.moved_to_account_id IS NULL
ORDER BY rank DESC
LIMIT ? OFFSET ?
LIMIT :limit OFFSET :offset
SQL

records = find_by_sql([sql, limit, offset])
records = find_by_sql([sql, { limit: limit, offset: offset }])
ActiveRecord::Associations::Preloader.new.preload(records, :account_stat)
records
end

def advanced_search_for(terms, account, limit = 10, following = false, offset = 0)
def advanced_search_for(terms, account, limit = 10, offset = 0, options = {})
textsearch, query = generate_query_for_search(terms)

if following
sql = <<-SQL.squish
WITH first_degree AS (
SELECT target_account_id
FROM follows
WHERE account_id = ?
UNION ALL
SELECT ?
)
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 = ?)
WHERE accounts.id IN (SELECT * FROM first_degree)
AND #{query} @@ #{textsearch}
AND accounts.suspended_at IS NULL
AND accounts.moved_to_account_id IS NULL
GROUP BY accounts.id
ORDER BY rank DESC
LIMIT ? OFFSET ?
SQL

records = find_by_sql([sql, account.id, account.id, account.id, limit, offset])
else
sql = <<-SQL.squish
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}
AND accounts.suspended_at IS NULL
AND accounts.moved_to_account_id IS NULL
GROUP BY accounts.id
ORDER BY rank DESC
LIMIT ? OFFSET ?
SQL

records = find_by_sql([sql, account.id, account.id, limit, offset])
end

sql = if options[:following] || options[:followers]
sql_first_degree = first_degree(options)

<<-SQL.squish
#{sql_first_degree}
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 = :account_id)
WHERE accounts.id IN (SELECT * FROM first_degree)
AND #{query} @@ #{textsearch}
AND accounts.suspended_at IS NULL
AND accounts.moved_to_account_id IS NULL
GROUP BY accounts.id
ORDER BY rank DESC
LIMIT :limit OFFSET :offset
SQL
else
<<-SQL.squish
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 = :account_id) OR (accounts.id = f.target_account_id AND f.account_id = :account_id)
WHERE #{query} @@ #{textsearch}
AND accounts.suspended_at IS NULL
AND accounts.moved_to_account_id IS NULL
GROUP BY accounts.id
ORDER BY rank DESC
LIMIT :limit OFFSET :offset
SQL
end

records = find_by_sql([sql, { account_id: account.id, limit: limit, offset: offset }])
ActiveRecord::Associations::Preloader.new.preload(records, :account_stat)
records
end
Expand All @@ -505,6 +498,44 @@ def from_text(text)

private

def first_degree(options)
if options[:following] && options[:followers]
<<-SQL
WITH first_degree AS (
SELECT target_account_id
FROM follows
WHERE account_id = :account_id
UNION ALL
SELECT account_id
FROM follows
WHERE target_account_id = :account_id
UNION ALL
SELECT :account_id
)
SQL
elsif options[:following]
<<-SQL
WITH first_degree AS (
SELECT target_account_id
FROM follows
WHERE account_id = :account_id
UNION ALL
SELECT :account_id
)
SQL
elsif options[:followers]
<<-SQL
WITH first_degree AS (
SELECT account_id
FROM follows
WHERE target_account_id = :account_id
UNION ALL
SELECT :account_id
)
SQL
end
end

def generate_query_for_search(terms)
terms = Arel.sql(connection.quote(terms.gsub(/['?\\:]/, ' ')))
textsearch = "(setweight(to_tsvector('simple', accounts.display_name), 'A') || setweight(to_tsvector('simple', accounts.username), 'B') || setweight(to_tsvector('simple', coalesce(accounts.domain, '')), 'C'))"
Expand Down
9 changes: 8 additions & 1 deletion app/services/account_search_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def from_database
end

def advanced_search_results
Account.advanced_search_for(terms_for_query, account, limit_for_non_exact_results, options[:following], offset)
Account.advanced_search_for(terms_for_query, account, limit_for_non_exact_results, offset, options)
end

def simple_search_results
Expand All @@ -74,12 +74,15 @@ def from_elasticsearch

if account
return [] if options[:following] && following_ids.empty?
return [] if options[:followers] && followers_ids.empty?

if options[:following]
must_clauses << { terms: { id: following_ids } }
elsif following_ids.any?
should_clauses << { terms: { id: following_ids, boost: 100 } }
end

must_clauses << { terms: { id: followers_ids } } if options[:followers]
end

query = { bool: { must: must_clauses, should: should_clauses } }
Expand Down Expand Up @@ -134,6 +137,10 @@ def following_ids
@following_ids ||= account.active_relationships.pluck(:target_account_id) + [account.id]
end

def followers_ids
@followers_ids ||= account.passive_relationships.pluck(:account_id) + [account.id]
end

def limit_for_non_exact_results
if exact_match?
limit - 1
Expand Down

0 comments on commit d7c3145

Please sign in to comment.