Improve Account#triadic_closures (#3079)

This commit is contained in:
alpaca-tc 2017-05-16 19:06:38 +09:00 committed by Eugen Rochko
parent 09ec6e504b
commit 682b68438e
2 changed files with 44 additions and 14 deletions

View file

@ -259,24 +259,30 @@ class Account < ApplicationRecord
nil nil
end end
def triadic_closures(account, limit = 5) def triadic_closures(account, limit: 5, offset: 0)
sql = <<-SQL.squish sql = <<-SQL.squish
WITH first_degree AS ( WITH first_degree AS (
SELECT target_account_id SELECT target_account_id
FROM follows FROM follows
WHERE account_id = :account_id WHERE account_id = :account_id
) )
SELECT accounts.* SELECT accounts.*
FROM follows FROM follows
INNER JOIN accounts ON follows.target_account_id = accounts.id INNER JOIN accounts ON follows.target_account_id = accounts.id
WHERE account_id IN (SELECT * FROM first_degree) AND target_account_id NOT IN (SELECT * FROM first_degree) AND target_account_id <> :account_id WHERE
account_id IN (SELECT * FROM first_degree)
AND target_account_id NOT IN (SELECT * FROM first_degree)
AND target_account_id NOT IN (:excluded_account_ids)
GROUP BY target_account_id, accounts.id GROUP BY target_account_id, accounts.id
ORDER BY count(account_id) DESC ORDER BY count(account_id) DESC
OFFSET :offset
LIMIT :limit LIMIT :limit
SQL SQL
excluded_account_ids = account.excluded_from_timeline_account_ids + [account.id]
find_by_sql( find_by_sql(
[sql, { account_id: account.id, limit: limit }] [sql, { account_id: account.id, excluded_account_ids: excluded_account_ids, limit: limit, offset: offset }]
) )
end end

View file

@ -261,19 +261,43 @@ RSpec.describe Account, type: :model do
end end
describe '.triadic_closures' do describe '.triadic_closures' do
it 'finds accounts you dont follow which are followed by accounts you do follow' do subject { described_class.triadic_closures(me) }
me = Fabricate(:account)
friend = Fabricate(:account) let!(:me) { Fabricate(:account) }
friends_friend = Fabricate(:account) let!(:friend) { Fabricate(:account) }
let!(:friends_friend) { Fabricate(:account) }
let!(:both_follow) { Fabricate(:account) }
before do
me.follow!(friend) me.follow!(friend)
friend.follow!(friends_friend) friend.follow!(friends_friend)
both_follow = Fabricate(:account)
me.follow!(both_follow) me.follow!(both_follow)
friend.follow!(both_follow) friend.follow!(both_follow)
end
results = Account.triadic_closures(me) it 'finds accounts you dont follow which are followed by accounts you do follow' do
expect(results).to eq [friends_friend] is_expected.to eq [friends_friend]
end
context 'when you block account' do
before do
me.block!(friends_friend)
end
it 'rejects blocked accounts' do
is_expected.to be_empty
end
end
context 'when you mute account' do
before do
me.mute!(friends_friend)
end
it 'rejects muted accounts' do
is_expected.to be_empty
end
end end
end end