From d5063072c3d7a882456f09cb70e664a2aeec7d81 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 18 Mar 2024 13:57:21 +0100 Subject: [PATCH] Revert friends-of-friends follow recommendation query to using a CTE (#29619) --- .../friends_of_friends_source.rb | 37 +++++++++++++++---- .../friends_of_friends_source_spec.rb | 12 +++--- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/app/models/account_suggestions/friends_of_friends_source.rb b/app/models/account_suggestions/friends_of_friends_source.rb index b4f549bf31..825b24f419 100644 --- a/app/models/account_suggestions/friends_of_friends_source.rb +++ b/app/models/account_suggestions/friends_of_friends_source.rb @@ -7,14 +7,35 @@ class AccountSuggestions::FriendsOfFriendsSource < AccountSuggestions::Source end def source_query(account, limit: DEFAULT_LIMIT) - first_degree = account.following.where.not(hide_collections: true).select(:id).reorder(nil) - base_account_scope(account) - .joins(:account_stat) - .joins(:passive_relationships).where(passive_relationships: { account_id: first_degree }) - .group('accounts.id, account_stats.id') - .reorder(frequency: :desc, followers_count: :desc) - .limit(limit) - .pluck(Arel.sql('accounts.id, COUNT(*) AS frequency, followers_count')) + Account.find_by_sql([<<~SQL.squish, { id: account.id, limit: limit }]).map { |row| [row.id, row.frequency, row.followers_count] } + WITH first_degree AS ( + SELECT target_account_id + FROM follows + JOIN accounts AS target_accounts ON follows.target_account_id = target_accounts.id + WHERE account_id = :id + AND NOT target_accounts.hide_collections + ) + SELECT accounts.id, COUNT(*) AS frequency, account_stats.followers_count as followers_count + FROM accounts + JOIN follows ON follows.target_account_id = accounts.id + JOIN account_stats ON account_stats.account_id = accounts.id + LEFT OUTER JOIN follow_recommendation_mutes ON follow_recommendation_mutes.target_account_id = accounts.id AND follow_recommendation_mutes.account_id = :id + WHERE follows.account_id IN (SELECT * FROM first_degree) + AND NOT EXISTS (SELECT 1 FROM blocks b WHERE b.target_account_id = follows.target_account_id AND b.account_id = :id) + AND NOT EXISTS (SELECT 1 FROM blocks b WHERE b.target_account_id = :id AND b.account_id = follows.target_account_id) + AND NOT EXISTS (SELECT 1 FROM mutes m WHERE m.target_account_id = follows.target_account_id AND m.account_id = :id) + AND (accounts.domain IS NULL OR NOT EXISTS (SELECT 1 FROM account_domain_blocks b WHERE b.account_id = :id AND b.domain = accounts.domain)) + AND NOT EXISTS (SELECT 1 FROM follows f WHERE f.target_account_id = follows.target_account_id AND f.account_id = :id) + AND follows.target_account_id <> :id + AND accounts.discoverable + AND accounts.suspended_at IS NULL + AND accounts.silenced_at IS NULL + AND accounts.moved_to_account_id IS NULL + AND follow_recommendation_mutes.target_account_id IS NULL + GROUP BY accounts.id, account_stats.id + ORDER BY frequency DESC, account_stats.followers_count ASC + LIMIT :limit + SQL end private diff --git a/spec/models/account_suggestions/friends_of_friends_source_spec.rb b/spec/models/account_suggestions/friends_of_friends_source_spec.rb index d7915985f8..c2f8d0f86c 100644 --- a/spec/models/account_suggestions/friends_of_friends_source_spec.rb +++ b/spec/models/account_suggestions/friends_of_friends_source_spec.rb @@ -76,19 +76,19 @@ RSpec.describe AccountSuggestions::FriendsOfFriendsSource do it 'contains correct underlying source data' do expect(source_query_values) .to contain_exactly( - [eugen.id, 2, 3], # Followed by 2 friends of bob (eve, mallory), 3 followers total (breaks tie) - [john.id, 2, 2], # Followed by 2 friends of bob (eve, mallory), 2 followers total - [neil.id, 1, 2], # Followed by 1 friends of bob (mallory), 2 followers total (breaks tie) - [jerk.id, 1, 1] # Followed by 1 friends of bob (eve), 1 followers total + [john.id, 2, 2], # Followed by 2 friends of bob (eve, mallory), 2 followers total (breaks tie) + [eugen.id, 2, 3], # Followed by 2 friends of bob (eve, mallory), 3 followers total + [jerk.id, 1, 1], # Followed by 1 friends of bob (eve), 1 followers total (breaks tie) + [neil.id, 1, 2] # Followed by 1 friends of bob (mallory), 2 followers total ) end def expected_results [ - [eugen.id, :friends_of_friends], [john.id, :friends_of_friends], - [neil.id, :friends_of_friends], + [eugen.id, :friends_of_friends], [jerk.id, :friends_of_friends], + [neil.id, :friends_of_friends], ] end