1. 创建程序的执行入口SparkContext对象
1.在pycharm中创建
from pyspark import SparkContext,SparkConf
if __name__=='__main':
conf=SparkConf().setAppName("hello").setMaster("local[*]")
sc=SparkContext(conf=conf)
2.在jupyter中创建
import findspark
findspark.init()
import pyspark
from pyspark import SparkContext
sc=SparkContext("local","app")
2.RDD算子
rdd算子分为两大类,Transformation算子与Action算子
区别:
Transformation算子返回值仍然是RDD,只是将RDD经过了转换;
Action算子的返回值不是RDD
Transformation相当于在构建计划,action是一个指令,让这个计划开始工作。没有Action算子,Transformation算子就不工作
(1)Transformation算子
- map算子
参数为函数,返回值是RDD
rdd=sc.parallelize([1,2,3,4,5,6],3)
def add(data):
return data*10
rdd.map(add).collect()
#方法二:使用lambda编写匿名函数
rdd.map(lambda data:data*10).collect()
[10, 20, 30, 40, 50, 60]
3个分区都作用了map函数,并将分区的每个元素都调用add函数,乘以10。最终汇总各分区结果仍返回RDD
- flatMap算子
先对RDD执行map,然后解除嵌套
rdd1=sc.parallelize(["hadoop spark hadoop","spark hadoop hadoop","hadoop flink spark"])
#使用map
rdd1.map(lambda s:s.split(" ")).collect()
[['hadoop', 'spark', 'hadoop'],
['spark', 'hadoop', 'hadoop'],
['hadoop', 'flink', 'spark']]
#使用flatMap
rdd1.flatMap(lambda s:s.split(" ")).collect()
['hadoop',
'spark',
'hadoop',
'spark',
'hadoop',
'hadoop',
'hadoop',
'flink',
'spark']
- reduceByKey算子
针对k,v型数据,自动按照key分组,然后将组内value聚合
rdd3=sc.parallelize([('a',1),('a',1),('b',1),('b',1),('b',1)])
rdd3.reduceByKey(lambda a,b:a+b).collect()
[('a', 2), ('b', 3)]
叠加式相加:对于’a’:1+1=2, 对于‘b’:1+1=2,2+1=3
- mapValues算子
传入RDD,但只对values进行操作,注意与map的区别
rdd4=sc.parallelize([('a',1),('a',11),('b',5),('b',6),('b',1)])
rdd4.mapValues(lambda x:x*10).collect()
[('a', 10), ('a', 110), ('b', 50), ('b', 60), ('b', 10)]
- groupBy算子
作用:对数据进行分组
传入的函数的意思是,通过这个函数,确认通过什么分组
rdd5=sc.parallelize([('a',1),('a',1),('b',1),('b',1),('b',1)])
rdd5.groupBy(lambda t:t[0]).collect()
[('a', <pyspark.resultiterable.ResultIterable at 0x1dcaed71b48>),
('b', <pyspark.resultiterable.ResultIterable at 0x1dcaecd6d48>)]
#将可迭代的values放入列表中
rdd6.map(lambda t:(t[0],list(t[1]))).collect()
[('a', [('a', 1), ('a', 1)]), ('b', [('b', 1), ('b', 1), ('b', 1)])]
- filter算子
作用:过滤想要的数据,逻辑值为True的保留
rdd7=sc.parallelize([1,2,3,4,5,6,7,8])
rdd7.filter(lambda x:x%2==1).collect()
[1, 3, 5, 7]
- distinct算子
作用:对数据去重
rdd8=sc.parallelize([1,2,1,3,4,7,7,9,8,8,3])
rdd8.distinct().collect()
[1, 2, 3, 4, 7, 9, 8]
- union算子
将两个RDD合并成一个RDD返回,不去重
rdd9=sc.parallelize([1,2,3])
rdd10=sc.parallelize(['a',1,'b','m'])
union_rdd=rdd9.union(rdd10)
union_rdd.collect()
[1, 2, 3, 'a', 1, 'b', 'm']
- join算子
作用:对两个RDD进行连接操作,类似SQL语句
#部门ID和员工姓名
x=sc.parallelize([(1001,"zhangsan"),(1002,"lisi"),(1003,"wangwu")])
#部门ID和部门名称
y=sc.parallelize([(1001,"sales"),(1002,"tech")])
#join内连接
x.join(y).collect()
[(1002, ('lisi', 'tech')), (1001, ('zhangsan', 'sales'))]
#左外连接
x.leftOuterJoin(y).collect()
[(1002, ('lisi', 'tech')),
(1001, ('zhangsan', 'sales')),
(1003, ('wangwu', None))]
- intersection算子
作用:计算两个RDD的交集,返回一个新的RDD
r1=sc.parallelize([('a',1),('b',1)])
r2=sc.parallelize([('a',1),('c',1)])
uni_rdd=r1.intersection(r2)
uni_rdd.collect()
[('a', 1)]
- glom算子
作用:将RDD的数据加上嵌套,这个嵌套是根据分组进行的
rdd12=sc.parallelize([1,2,3,4,5,6,7,8],3)
rdd.glom().collect()
[[1, 2], [3, 4], [5, 6]]
- groupByKey算子
针对k,v型数据,自动按照key分组
rdd13=sc.parallelize([('a',1),('a',11),('b',5),('b',6),('b',1)])
group_rdd=rdd13.groupByKey()
group_rdd.map(lambda x:(x[0],list(x[1]))).collect()
[('a', [1, 11]), ('b', [5, 6, 1])]
- sortBy算子
基于自己指定的排序方法,对RDD数据进行排序
注意只能确保分区内有序,分区间不一定有序
rdd14=sc.parallelize([('c',1),('f',1),('a',11),('b',3),('e',5),('k',7)])
#参数一:表示按照哪个列排序
#参数二:True表示升序,False表示降序
#参数三:排序的分区数
rdd14.sortBy(lambda x:x[1],ascending=True,numPartitions=3).collect()
[('c', 1), ('f', 1), ('b', 3), ('e', 5), ('k', 7), ('a', 11)]
rdd14.sortBy(lambda x:x[0],ascending=False,numPartitions=3).collect()
[('k', 7), ('f', 1), ('e', 5), ('c', 1), ('b', 3), ('a', 11)]
- sortByKey算子
针对k,v型数据,按照key进行排序
rdd15=sc.parallelize([('c',1),('f',1),('a',11),('b',3),('e',5),('k',7),
('y',1),('u',4),('m',1),('o',1)])
rdd15.sortByKey(ascending=True,numPartitions=1,keyfunc=lambda key:str(key).lower()).collect()
[('a', 11),
('b', 3),
('c', 1),
('e', 5),
('f', 1),
('k', 7),
('m', 1),
('o', 1),
('u', 4),
('y', 1)]
(2)Action算子
- countByKey算子
统计key出现的次数
#统计单词出现的次数
rdd16=sc.parallelize("word.txt")
rdd17=rdd16.faltMap(lambda x:x.split(" ")).map(lambda x:(x,1))
res=rdd17.countByKey()
print(res)
- collect算子
将RDD各个分区的数据统一收集到Driver中,形成一个list对象
rdd.collect()
- reduce算子
对values进行叠加式聚合,返回值不是RDD
rdd16=sc.parallelize([1,2,3,4,5])
print(rdd.reduce(lambda a,b:a+b))
21
- flod算子
和reduce一样,接收传入逻辑进行聚合,聚合是带有初始值的
初始值在分区内与分区间聚合时都要加上
rdd17=sc.parallelize(range(1,10),3)
print(rdd.fold(10,lambda a,b:a+b))
85
- first算子
取出RDD的第一个元素
sc.parallelize([3,2,1]).first()
3
- take算子
取出RDD的前n个元素
sc.parallelize([3,2,1,5,8,9]).take(5)
[3, 2, 1, 5, 8]
- top算子
对RDD数据集降序排序,取出前n个
sc.parallelize([3,4,1,5,8,9]).top(3)
[9, 8, 5]
- count算子
计算RDD有多少条数据
sc.parallelize([3,4,1,5,8,9]).count()
6
- takeSample算子
随机抽取RDD数据
#参数1:True表示取同一个位置数据,False表示不允许取同一个数据
#参数2:抽样要几个
#参数3:随机数种子,若设定,每次取出的随机数据一样
rdd18=sc.parallelize([1,3,5,6,4,3,7,8,2,1])
print(rdd18.takeSample(False,5,22))
[3, 7, 1, 8, 3]
- takeOrdered算子
对RDD进行排序(可正向可逆向)取出前n个
rdd19=sc.parallelize([1,3,5,6,4,3,7,8,2,1],1)
print(rdd19.takeOrdered(3))
[1, 1, 2]
#倒序
print(rdd19.takeOrdered(3,lambda x:-x))
[8, 7, 6]
- foreach算子
对每一个元素,执行指定的逻辑,类似map,但没有返回值
rdd20=sc.parallelize([3,4,1,5,8,9],1)
res1=rdd.foreach(lambda x:print(x*10))
- saveAsTextFile算子
将RDD数据写入本地文件系统或HDFS中,有多少分区生成多少文件
rdd.savaAsTextFile("hdfs://node1:8020/output")
广播变量
把list对象传给每个分区使用时,同一个executer只用传送一个,避免资源浪费,占用网络带宽
stu_info_list=[(1,"张洁",11),
(2,"刘培",13),
(3,"张燕",11),
(4,"王薇",11)]
#将本地list对象标记为广播变量
broadcast=sc.broadcast(stu_info_list)
score_info_rdd=sc.parallelize([
(1,'语文',99),
(2,'数学',99),
(3,'英语',99),
(4,'编程',99),
(1,'语文',99),
(2,'编程',99),
(3,'语文',99),
(4,'英语',99),
(1,'语文',99),
(3,'英语',99),
(2,'编程',99),
])
def map_func(data):
id=data[0]
name=""
#for i in stu_info_list:
for i in broadcast.value:
if id==i[0]:
name=i[1]
return (name,data[1],data[2])
print(score_info_rdd.map(map_func).collect())
[('张洁', '语文', 99), ('刘培', '数学', 99), ('张燕', '英语', 99), ('王薇', '编程', 99), ('张洁', '语文', 99), ('刘培', '编程', 99), ('张燕', '语文', 99), ('王薇', '英语', 99), ('张洁', '语文', 99), ('张燕', '英语', 99), ('刘培', '编程', 99)]
累加器
rdd=sc.parallelize([1,2,3,4,5,6,7,8,9,10],2)
count=0
def map_func(data):
global count
count +=1
print(count)
rdd.map(map_func).collect()
print(count)
0
#最后的count值为0,各个分区虽然累加了,但最后没有汇总给Driver
#使用累加器
acmlt=sc.accumulator(0)
def map_func(data):
global acmlt
acmlt +=1
print(acmlt)
rdd.map(map_func).collect()
print(acmlt)
10