Postgresql 选择你可能认识的人,按共同朋友的数量排序

Posted

技术标签:

【中文标题】Postgresql 选择你可能认识的人,按共同朋友的数量排序【英文标题】:Postgresql select people you may know orderded by number of mutual friends 【发布时间】:2013-11-05 12:57:51 【问题描述】:

我正在建立一个社交网络,我希望我的成员能够轻松找到新朋友。 就像在 Facebook 中一样,我想向他们推荐一些他们可能认识的人,因为他们拥有的共同朋友的数量。

我的 PostgreSQL 好友数据库结构如下:

> PROFILES_FRIENDSHIPS
> ----------------------
> - fri_profile_from // int, Person who sent the friendship request
> - fri_profile_to // int, Person who received the friendship request
> - fri_accepted // tinyint, has the person accepted the friendship request?

这是我在 PostgreSQL 中找到的用于查找 2 个个人资料(ID 为 24 的个人资料和 ID 为 26 的个人资料)之间共同朋友数量的查询:

SELECT COUNT(*)
FROM profiles AS p
INNER JOIN (
        SELECT (
        CASE    WHEN ( 26 = f.fri_profile_from ) THEN f.fri_profile_to 
                    ELSE f.fri_profile_from END) AS fri_profile_from 
        FROM profiles_friendships AS f 
        WHERE 1 = 1
        AND (f.fri_profile_to = 26 OR f.fri_profile_from = 26) 
        AND fri_accepted = 1) 
AS f1 
ON (f1.fri_profile_from = p.pro_id) 
INNER JOIN (
        SELECT (
        CASE    WHEN ( 24 = f.fri_profile_from ) THEN f.fri_profile_to 
                    ELSE f.fri_profile_from END) AS fri_profile_from 
        FROM profiles_friendships AS f 
        WHERE 1 = 1
        AND (f.fri_profile_to = 24 OR f.fri_profile_from = 24) 
        AND fri_accepted = 1) 
AS f2 
ON (f2.fri_profile_from = p.pro_id)

现在我一直在尝试转换此查询,以使其找到与我最共同的朋友但不是我朋友的个人资料。但没有成功......我也在这个网站上研究了很多例子,但大多数都在使用友谊表中的双重记录。就像 24 和 26 是朋友一样,有 2 条记录:(24, 26) 和 (26, 24)。这让他们更容易加入并找到共同的朋友,但这不是我想要建立我的数据库的方式。

如果有人可以帮助我开始这个查询,我将非常感激。

【问题讨论】:

【参考方案1】:
WITH friends AS(
  SELECT p.pro_id, CASE WHEN f.fri_profile_from = p.pro_id THEN f.fri_profile_to 
                    ELSE f.fri_profile_from END AS friend_id
  FROM profiles
)
SELECT f2.pro_id, count(*) as friend_count
FROM friends AS f1
  JOIN friends AS f2
    ON f1.friend_id=f2.friend_id
       AND f1.pro_id != f2.pro_id
       AND f1.pro_id != f2.friend_id
WHERE f1.pro_id = :user_id
GROUP BY f2.pro_id
ORDER BY friend_count;

【讨论】:

【参考方案2】:

第 1 步获取所有不是朋友的人

Select * 
From profiles
where (from/to_friendship is not myID)

第 2 步包括一列,其中包含 # 个共同朋友并按其排序

select *, 
  (select count(*) from [mutual friends query]) as NrOfMutualFriends)
From profiles
where (from/to_friendship is not myID)
Order by NrOfMutualFriends

编辑:共同好友查询:

第 1 步选择我所有的朋友和他的所有朋友

select if(from = myId, to, from) as myfriendids
from PROFILES_FRIENDSHIPS where from = myid or to = myid

select if(from = hisId, to, from) as hisfriendids
from PROFILES_FRIENDSHIPS where from = hisId or to = hisId

步骤 2 将这些查询合并为 1

select count(*) 
from 
  ( select if(from = myId, to, from) as myfriendids
    from PROFILES_FRIENDSHIPS where from = myid or to = myid) myfriends
inner join 
  ( select if(from = hisId, to, from) as hisfriendids
  from PROFILES_FRIENDSHIPS where from = hisId or to = hisId) hisfriends
on myfriendsids = hisfriendsids

【讨论】:

用[mutual friends query],你的意思是我查询2个ID之间的共同好友数?但是我有我的 2 个 ID,我不知道如何将它们包含在我的新查询中.. 增加了共同好友的选择【参考方案3】:

您可以轻松创建双记录格式的内联视图:

with cte_friends(user_id, friend_id) as (
    select
        fri_profile_from, fri_profile_to
    from PROFILES_FRIENDSHIPS
    where fri_accepted = 1

    union all -- or union if there could be duplicates

    select
        fri_profile_to, fri_profile_from
    from PROFILES_FRIENDSHIPS
    where fri_accepted = 1
)
select
    f2.friend_id, count(distinct f2.user_id)
from cte_friends as f1
    inner join cte_friends as f2 on f2.user_id = f1.friend_id
    left outer join cte_friends as f3 on f3.user_id = f2.friend_id and f3.friend_id = f1.user_id
where
    f1.user_id = 1 and f3.user_id is null and
    f2.friend_id != 1
group by f2.friend_id
order by 2 desc

sql fiddle demo

【讨论】:

以上是关于Postgresql 选择你可能认识的人,按共同朋友的数量排序的主要内容,如果未能解决你的问题,请参考以下文章

社交软件上“你可能认识的人”到底是怎么找到你的?

拼多多2018/8/5算法工程师笔试

没有密码,怎样查看到别人的QQ好友列表?

推荐朋友 - LintCode

什么样的人才是一个成熟的人?

MySQL 向左,PostgreSQL 向右