零、实验环境
-
ubuntu1804
-
pyspark2.4.7
-
JupyterLab
-
Anconda3
实验环境可参考:Spark环境搭建
JupyterLab使用可参考:JupyterLab使用教程
一、问题描述
1. 示例数据
有一份用户/粉丝数据fans_data.txt:
A:B,C,D,F,E,O
B:A,C,E,K
C:F,A,D,I
D:A,E,F,L
E:B,C,D,M,L
F:A,B,C,D,E,O,M
G:A,C,D,E,F
H:A,C,D,E,O
I:A,O
J:B,O
K:A,C,D
L:D,E,F
M:E,F,G
O:A,H,I,J
- 冒号
:
前表示用户 - 冒号
:
后表示关注该用户的粉丝,粉丝之间用逗号,
隔开
2. 需求
求出每两个用户的共同粉丝,比如:
A-B:C,E
...
A-B:C,E
表示用户A和B拥有共同的粉丝C和E
二、解决方案
1. 思路
用户:粉丝列表
=> 粉丝:用户列表
=> 用户-用户:粉丝列表
2. 实验步骤
1)导入数据
from pyspark import SparkContext
#创建SparkContext对象
sc = SparkContext(master='local[1]', appName='share_fans')
#导入数据
r1 = sc.textFile('file:///home/xiaobai/data/fans_data.txt')
#观察前5个元素
r1.take(5)
输出结果:
['A:B,C,D,F,E,O', 'B:A,C,E,K', 'C:F,A,D,I', 'D:A,E,F,L', 'E:B,C,D,M,L']
2)用户:粉丝列表 => 粉丝:用户
#定义将一行数据转换成(粉丝,用户)形式
def to_fan_user(line):
result = []
tmp = line.split(':')
if len(tmp) == 2:
user,fans = tmp
for fan in fans.split(','):
result.append((fan,(user,)))
return result
r2 = r1.flatMap(to_fan_user)
#观察数据
r2.take(5)
输出结果:
[('B', ('A',)), ('C', ('A',)), ('D', ('A',)), ('F', ('A',)), ('E', ('A',))]
3)粉丝:用户 => 粉丝:用户列表
#将同一粉丝的用户放在一个元组中
r3 = r2.reduceByKey(lambda x,y: x+y)
r3.take(5)
输出结果:
[('B', ('A', 'E', 'F', 'J')),
('C', ('A', 'B', 'E', 'F', 'G', 'H', 'K')),
('D', ('A', 'C', 'E', 'F', 'G', 'H', 'K', 'L')),
('F', ('A', 'C', 'D', 'G', 'L', 'M')),
('E', ('A', 'B', 'D', 'F', 'G', 'H', 'L', 'M'))]
)
#粉丝:用户列表 => 用户-用户:粉丝
4)粉丝:用户列表 => 用户-用户:粉丝
def to_user2_fan(x):
return [((a,b),(x[0],)) for a in x[1] for b in x[1] if a < b]
r4 = r3.flatMap(to_user2_fan)
r4.take(5)
输出结果:
[(('A', 'E'), ('B',)),
(('A', 'F'), ('B',)),
(('A', 'J'), ('B',)),
(('E', 'F'), ('B',)),
(('E', 'J'), ('B',))]
5)用户-用户:粉丝 => 用户-用户:粉丝列表
r5 = r4.reduceByKey(lambda x,y: x+y).sortByKey()
r5.take(5)
输出结果:
[(('A', 'B'), ('C', 'E')),
(('A', 'C'), ('D', 'F')),
(('A', 'D'), ('F', 'E')),
(('A', 'E'), ('B', 'C', 'D')),
(('A', 'F'), ('B', 'C', 'D', 'E', 'O'))]
6)按指定格式输出
r6 = r5.map(lambda x: '-'.join(x[0]) + ':' + ','.join(x[1]))
r6.saveAsTextFile('file:///home/xiaobai/output/sharefans')
查看输出目录
%ls -R /home/xiaobai/output/sharefans/
查看输出内容
!head /home/xiaobai/output/sharefans/part-*