经典sql题(十)查找共同好友或相互关注 一

SQL 的 JOIN

  • JOIN 类型:这题我们使用的是 LEFT JOIN,也称为左外连接。它用于从左侧表(tl)中返回所有行,并且在右侧表(t2)中查找匹配的行。如果没有匹配,右侧表的结果将为 NULL
  • INNER JOIN vs LEFT JOININNER JOIN 仅返回两个表中匹配的行,而 LEFT JOIN 保留左侧表的所有行。
  • 在使用 LEFT JOIN 时,如果在右侧没有找到匹配的行,结果将返回 NULL。在这种情况下,通常需要通过条件判断来处理这些 NULL 值,比如通过 IFCASE 来判断双向关系是否存在。

示例数据

假设我们的 fans 表有以下数据:

from_userto_user
12
21
13
31
45
54
23

思路:提取用户之间的关系

我们希望通过查询找出每个用户之间的关系,并确定他们是否为好友关系。

查询:

SELECT 
    tl.from_user,
    tl.to_user,
    IF(t2.from_user IS NOT NULL, 1, 0) AS is_friend
FROM 
    fans tl
LEFT JOIN 
    fans t2 ON tl.from_user = t2.to_user AND tl.to_user = t2.from_user;
结果(表 table1):
from_userto_useris_friend
121
211
130
310
451
541
230

第一步:分析好友关系

在这个查询中,我们通过左连接(LEFT JOIN)将 fans 表与自身连接,以检查每个用户和他们的朋友之间的关系。如果 t2.from_user 不为 NULL,则表示 from_userto_user 之间存在双向关系,我们将其标记为好友(is_friend = 1),否则标记为非好友(is_friend = 0)。

关键步骤:
  1. 左连接:将 tlt2 通过用户的 from_userto_user 进行连接,以便在 t2 中找到反向的好友关系。

    • tl 表是 fans 的一个别名,表示“用户关注的用户”。
    • t2 表是 fans 的另一个别名,表示“关注此用户的用户”。
  2. 条件判断:使用 IF 语句来确定是否存在双向关系,并相应地标记 is_friend

第二步:中间表结构

在执行查询时,形成了两个视图:

tl(当前用户关注的列表):
from_userto_user
12
21
13
31
45
54
23
t2(关注当前用户的列表):
from_userto_user
21
12
31
13
54
45
32

第三步:连接步骤

1. 原始表(fans 表)

这是我们在执行连接前的原始数据:

from_userto_user
12
21
13
31
45
54
23

2. 连接条件

我们要执行的连接是左连接(LEFT JOIN),连接条件是:

  • tl.from_user = t2.to_user
  • tl.to_user = t2.from_user

这意味着我们要找出每个用户是否关注了对方,以判断双向关系。

3. 连接后的表

在连接之前,我们将原始表复制一份,称为 tl,并将其与自身进行连接,称为 t2。连接后的表如下:

连接规则示意
tlfrom_userto_user连接条件t2t2.from_usert2.to_user
第一行121 = 2 (from_user) AND 2 = 1 (to_user)第一行21
第二行212 = 1 (from_user) AND 1 = 2 (to_user)第二行12
第三行131 = 3 (from_user) AND 3 = 1 (to_user)无匹配NULLNULL
第四行313 = 1 (from_user) AND 1 = 3 (to_user)无匹配NULLNULL
第五行454 = 5 (from_user) AND 5 = 4 (to_user)第一行54
第六行545 = 4 (from_user) AND 4 = 5 (to_user)第二行45
第七行232 = 3 (from_user) AND 3 = 2 (to_user)无匹配NULLNULL

4. 连接后的结果表

连接后结果表如下:

tl.from_usertl.to_usert2.from_usert2.to_useris_friend
12211
21121
13NULLNULL0
31NULLNULL0
45541
54451
23NULLNULL0

解析

  • 在执行 LEFT JOIN 之前,原始表的行数是保持不变的。
  • 通过连接条件,我们可以判断出哪些用户之间存在双向关系。
  • 余下的行在连接后保持在结果中,尽管部分行的连接结果为 NULL,但它们在最终结果中依然存在。

最终查询:

SELECT 
    tl.from_user,
    tl.to_user,
    IF(t2.from_user IS NOT NULL, 1, 0) AS is_friend
FROM 
    fans tl
LEFT JOIN 
    fans t2 ON tl.from_user = t2.to_user AND tl.to_user = t2.from_user;
最终结果(表 table1):
from_userto_useris_friend
121
211
130
310
451
541
230

最终结果分析

根据上述查询结果,我们可以分析出每对用户之间的好友关系:

  • 用户 1 和 用户 2 是好友,is_friend 值为 1。
  • 用户 1 和 用户 3 不是好友,is_friend 值为 0。
  • 用户 4 和 用户 5 是好友,is_friend 值为 1。
  • 用户 2 和 用户 3 不是好友,is_friend 值为 0。
ubuntu编写 PySpark,实现“你可能认识的人”社交网络推荐算法。主要思想是,如果两个人有很多共同好友, 那么系统应该推荐再这两个人之间建立联系。 数据 • 作业附带data目录下的soc-LiveJournal1Adj.txt文件 • 文件包含多行邻接列表,格式如下: <User><TAB><Friends> 其中<User>代表用户的唯整数 ID;<Friends>代表用户的朋友,为逗号隔开的整数列表。注意朋 友关系是相互(即朋友之间的边是无向的):如果 A 是 B 的朋友,那么 B 也是 A 的朋友。提供的 数据中保证如果 A 在 B 的朋友列表中出现,B 也会在 A 的朋友列表里。 算法 使用个简单的算法:对于每个用户 U,算法会推荐 N=10 个还不是 U 的朋友的用户,但他们与 U 有最多的共同好友。 输出 • 输出应该为每个用户包含行如下格式 <User><TAB><Recommendations> 其中<User>代表用户的唯整数 ID;<Recommendations>是逗号隔开的整数 ID 列表,代表算法推 荐的 User 可能认识的人,按照共同好友数量的降序排列。 • 如果用户的 2 度好友 (即上述通过中间好友建立关联的朋友) 少于 10 个,也请将这些推荐按结果按 共同好友数量的降序悉数列出。如果用户没有好友,你可以输出个空的列表。如果在推荐的结果中 共同好友的数量相同,请将被推荐好友按他们的 ID 数值升序排列。 流程简述 请用简明的几句话描述你是如何使用 PySpark 解决这个问的。 提示 • 复用环境初始化代码 • 逐行检你每个步骤的输出。比如使用.take(X)方法看 RDD 的前X个元素 • 为了便于验证,用户 ID 11 的推荐结果应该是: 27552,7785,27573,27574,27589,27590,27600,27617,27620,276
最新发布
03-15
<think>好的,我需要帮助用户在Ubuntu环境下使用PySpark实现基于共同好友的社交网络推荐算法,特别是处理soc-LiveJournal1Adj.txt数据集,生成最多10个“你可能认识的人”推荐。让我先理清用户的需求和可能的步骤。 首先,用户提到了使用PySpark,所以需要确保环境配置正确。Ubuntu系统上应该安装Java、Spark和PySpark。然后,数据集的结构是邻接列表,每行应该是用户ID后跟其好友列表,比如“1 2,3,4”这样的格式。正确解析这个文件是关键的第步。 接下来,计算两度好友关系,也就是找出用户的好友好友,但排除已经是直接好友的情况。这步可能需要用到Spark的转换操作,比如map、flatMap,以及处理键值对。共同好友的数量是推荐的重要依据,所以需要统计每对用户之间的共同好友数,并按数量排序取前10。 然后,生成推荐。可能需要先将原始数据转换为(用户,好友)的键值对,然后通过两次连接操作找到共同好友。例如,用户A的好友是B,B的好友是C,那么C是A的两度好友。然后排除那些已经是直接好友的C,再统计每个A和C之间的共同好友数,最后排序得到推荐列表。 需要注意的是性能问,因为社交网络数据通常很大。使用PySpark的分布式计算能力可以处理大规模数据,但要注意合理设计转换和动作操作,避免不必要的shuffle,合理使用缓存。例如,在计算共同好友时,可能需要多次连接分组,优化这些步骤可以提高效率。 另外,用户提到要基于soc-LiveJournal1Adj.txt数据集,这个数据集的结构可能需要先进行预处理,比如分割每行的用户ID和好友列表。可能需要使用split函数来解析每行,生成用户对。 然后,代码的大致步骤可能是: 1. 读取数据并解析成(用户,好友列表)的RDD。 2. 展开好友列表,生成(用户,直接好友)的列表。 3. 通过连接操作,找到两度好友,即用户的好友好友。 4. 过滤掉已经是直接好友的情况。 5. 计算每对用户之间的共同好友数。 6. 按共同好友数降序排序,取前10作为推荐。 在具体实现中,可能需要用到flatMap来生成两度好友对,然后使用reduceByKeygroupByKey来统计共同好友的数量。需要注意的是,两度好友可能有多个中间好友,所以统计时要避免重复计数。 此外,可能还需要处理自连接的情况,比如用户自己不应该出现在推荐列表中。同时,确保推荐列表中没有重复的用户,并按共同好友数正确排序。 最后,将结果保存输出,确保格式符合要求。可能还需要测试代码的正确性,尤其是在处理大数据时的性能表现,以及推荐结果的准确性。 在环境配置方面,用户需要确认PySpark是否正确安装,Spark的master是否设置为本地模式集群模式,以及是否正确读取了输入文件路径。路径可能需要根据实际存放位置进行调整。 总结起来,步骤大致分为数据解析、两度好友查找共同好友统计、推荐生成,以及结果输出。每步都需要仔细处理数据,并利用PySpark的高效操作来优化计算过程。</think>以下是使用PySpark在Ubuntu上实现社交网络推荐算法的完整步骤: ### 1. 环境准备 确保已安装: - Java 8+ - Apache Spark 3.0+ - Python 3.6+ - PySpark库(可通过`pip install pyspark`安装) ### 2. 数据解析 soc-LiveJournal1Adj.txt数据格式示例: ``` 用户ID \t 好友1,好友2,好友3... ``` 解析代码: ```python from pyspark.sql import SparkSession spark = SparkSession.builder.appName("FriendRecommendation").getOrCreate() # 读取原始数据 raw_data = spark.sparkContext.textFile("soc-LiveJournal1Adj.txt") # 解析为(user, [friends])结构 parsed_data = raw_data.map(lambda line: ( line.split()[0], line.split()[1].split(",") if len(line.split())>1 else [] )).filter(lambda x: x[0] != '') ``` ### 3. 生成两度关系 ```python # 生成直接好友关系对 direct_pairs = parsed_data.flatMap( lambda x: [(x[0], friend) for friend in x[1]] ) # 生成两度好友关系 second_degree = direct_pairs.join(parsed_data)\ .flatMap(lambda x: [(x[1][0], friend) for friend in x[1][1]])\ .subtract(direct_pairs) # 排除直接好友 ``` ### 4. 计算共同好友数 ```python # 统计共同好友数量 recommendations = second_degree.map(lambda x: (x, 1))\ .reduceByKey(lambda a,b: a+b)\ .map(lambda x: (x[0][0], (x[0][1], x[1])))\ .groupByKey()\ .mapValues(lambda vals: sorted(vals, key=lambda x: -x[1])[:10]) ``` ### 5. 结果输出 ```python # 打印前10个用户的推荐结果 for user, recs in recommendations.take(10): print(f"用户 {user} 的推荐:") for rec in recs: print(f"\t{rec[0]} (共同好友数:{rec[1]})") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值