创建RDD
# 内部创建
list1 = [1,2,3,4,5,6]
set1 = set(list1)
rdd1 = sc.parallelize(list1)
rdd2 = sc.parallelize(set1)
print(rdd1.collect())
print(rdd2.collect())
rdd2.getNumPartitions() # 获取分区
# 从文件读取数据创建RDD
rdd3 = sc.textFile(r'D:\ws\spark\test.txt')
rdd3.count()
rdd3.collect()
map,flatMap转换数据,sortBy()排序、collect()查询、take()查询某几个值
# map
rdd4 = sc.parallelize([1,3,4,9])
rdd4.collect()
rdd4_new = rdd4.map(lambda x:x**2) #不改变行数
rdd4_new.collect()
# sortBy
rdd5 = sc.parallelize([(1,3),(45,3),(10,9)])
rdd5_new = rdd5.sortBy(lambda x:x[0]).collect()
print(rdd5_new)
print(rdd5.sortBy(lambda x:x[0],ascending=False,numPartitions=3).collect()) #降序
- 小练习:读取两个记录成绩的文件中中的内容,以‘\t’进行拆分,再排序选择bigdata中成绩最高的五位同学的学号
# 读取
bigdata = sc.textFile(r'D:\ws\spark\result_bigdata.txt')
math = sc.textFile(r'D:\ws\spark\result_math.txt')
# bigdata.collect()
# math.collect()
# 拆分
bigdata_new = bigdata.map(lambda x:x.split('\t')).collect()
# 再排序选择
bigdata_new2 = bigdata_new.sortBy(lambda x:int((x[2])),ascending=False)
# print(bigdata_new2.collect())
# 选择前5名
bigdata_new2.map(lambda x:x[0]).take(5)
union()合并多个RDD,filter()进行过滤、distinct()进行去重
sc.parallelize([1,2,3,4,4,4,4,]).filter(lambda x:x==4).collect()
# out:[4, 4, 4, 4]
# 将两个文件中内容用union连接起来
bigdata_math = bigdata.union(math)
bigdata_math1 = bigdata_math.map(lambda x:x.split('\t'))
bigdata_math2 = bigdata_math1.filter(lambda x:int(x[2])==100)
bigdata_math2.collect()
# 选择得100分的同学
bigdata_math2.map(lambda x:x[0]).distinct().collect()
键值对与RDD,转换操作reduceByKey()、groupByKey()
rdd = sc.parallelize([('a',1),('b',2),('c',3),('a',12)])
rdd.keys().collect()
# out:['a', 'b', 'c', 'a']
rdd.values().collect()
# out:[1, 2, 3, 12]
# reduceByKey内必须是一个函数,把key相同的,以+法合并起来
rdd.reduceByKey(lambda x,y:x+y).collect()
# groupByKey不带任何参数, 这是一个可迭代的对象
rdd.groupByKey().collect()
# out:[('b', <pyspark.resultiterable.ResultIterable at 0x296857dc1c8>),
# ('c', <pyspark.resultiterable.ResultIterable at 0x296857dce48>),
# ('a', <pyspark.resultiterable.ResultIterable at 0x296857dc688>)]
g_rdd.map(lambda x:sum(x[1])).collect() # 求value的和
g_rdd.map(lambda x:(x[0],sum(x[1]))).collect() #输出元组形式
- 输出每一位同学所有科目的总成绩
score = bigdata.union(math).map(lambda x:x.split('\t'))
score.map(lambda x:(x[0],int(x[2]))).reduceByKey(lambda x,y:x+y).collect()
join()连接两个RDD,zip组合两个RDD、combineByKey合并
rdd1 = sc.parallelize([('a',1),('b',2),('c',3)])
rdd2 = sc.parallelize([('a',1),('d',4),('e',5)])
rdd1.join(rdd2).collect() # join连接
rdd1.leftOuterJoin(rdd2).collect() #左外连接
rdd1.rightOuterJoin(rdd2).collect() #右外连接
rdd1.fullOuterJoin(rdd2).collect() #全连接
# zip(拉链),若rdd1与rdd2长度、分区个数不一样长,报错
rdd1 = sc.parallelize(['a','b','c'])
rdd2 = sc.parallelize([1,2,3])
rdd1.zip(rdd2).collect()
combinByKey 高阶函数,有三个参数:
createCombiner
,这个函数把当前的值作为参数,此时我们可以对其做些附加操作(类型转换)并把它返回 (这一步类似于初始化操作)mergeValue
, 该函数把元素V合并到之前的元素C(createCombiner)上 (这个操作在每个分区内进行)mergeCombiners
,该函数把2个元素C合并 (这个操作在不同分区间进行)
# 输出每位同学的平均成绩
test = sc.parallelize([('panda',1),('panda',8),('pink',4),('pink',8),('pirate',5)])
# 使用CombineByKey计算数据中每个键的总和和计数 (key,(总和,累加器))
createCombiner = lambda v:(v,1)
mergeValue = lambda agg,v:(agg[0]+v,agg[1]+1)
mergeCombiners = lambda agg1,agg2:(agg1[0]+agg2[0],agg1[1]+agg2[1])
test_new = test.combineByKey(createCombiner,mergeValue,mergeCombiners)
test_new.collect()
# out:[('panda', (9, 2)), ('pink', (12, 2)), ('pirate', (5, 1))]
print(test_new.map(lambda x:x[0]).collect()) # 打印key值
# out:['panda', 'pink', 'pirate']
print(test_new.map(lambda x:x[1][0]).collect()) # 打印相同key的总和
# out:[9, 12, 5]
print(test_new.map(lambda x:x[1][1]).collect()) # 打印key的累加器
# out:[2, 2, 1]
# 平均值
test_new.map(lambda x:(x[0] ,x[1][0] / x[1][1])).collect()
# out:[('panda', 4.5), ('pink', 6.0), ('pirate', 5.0)]
Spark SQL
文件中有三列数据,分别是用户id(userid)、艺术家id(artistid)、用户听该歌次数(playcount),求一下三个小问:
- 统计非重复的用户id的个数
- 统计用户听过歌曲的总数
- 找出ID为“1000002”的用户最喜欢的10首歌曲(即播放次数最多的10首歌曲)
# 读取文件
df = sc.textFile(r'D:\ws\spark\user_artist_data\user_artist_data.txt')
df.take(4)
out>>> ['1000002 1 55',
'1000002 1000006 33',
'1000002 1000007 8',
'1000002 1000009 144']
# 转换成DataFrame的形式
data = df.map(lambda x:x.split(' ')).map(lambda x:(x[0],x[1],int(x[2]))).toDF()
# DataFrame列名重命名需用到的列名
columns = ['userid','artistid','playcount']
# DataFrame列名重命名
for x,y in zip(data.columns,columns):
data = data.withColumnRenamed(x,y)
data.printSchema() # 查看结构
out>>> root
|-- userid: string (nullable = true)
|-- artistid: string (nullable = true)
|-- playcount: long (nullable = true)
data.show(4)
out>>> +-------+--------+---------+
| userid|artistid|playcount|
+-------+--------+---------+
|1000002| 1| 55|
|1000002| 1000006| 33|
|1000002| 1000007| 8|
|1000002| 1000009| 144|
+-------+--------+---------+
only showing top 4 rows
# 第一题
df1 = data.groupBy('userid').count()
df1.count()
out>>> 148111
# 第二题
df2 = data.groupBy('userid').sum('playcount').show(4)
out>>> +-------+--------------+
| userid|sum(playcount)|
+-------+--------------+
|1000280| 995|
|1000665| 1419|
|1000795| 238|
|1000839| 528|
+-------+--------------+
only showing top 4 rows
# 第三题
# 注册临时表,表名为t_law
data.registerTempTable('t_law')
# 执行SQL语句
sqlContext = SparkSession(sc)
sqlContext.sql("select * from t_law where userid='1000002' order by playcount desc limit 10").show()
out>>> +-------+--------+---------+
| userid|artistid|playcount|
+-------+--------+---------+
|1000002| 1000024| 329|
|1000002| 1000010| 314|
|1000002| 4209| 265|
|1000002| 1000323| 236|
|1000002| 1890| 223|
|1000002| 242| 176|
|1000002| 1000088| 157|
|1000002| 1000315| 155|
|1000002| 1001008| 151|
|1000002| 3033| 145|
+-------+--------+---------+