Anaconda前置环境执行的代码
#初始化上下文
import findspark
findspark.init()
from pyspark import SparkConf,SparkContext
# conf=SparkConf().setMaster("local[*]").setAppName("test")
conf=SparkConf().setAppName("test").setMaster("local[*]")
sc=SparkContext(conf=conf)
#本地文件路径
path="file:///app/notebook/testdata/"
文章目录
- Anaconda前置环境执行的代码
- RDD算子
- 第一个算子: map算子
- 第二个算子: flatMap算子
- 第三个算子:reduceByKey算子, 针对KV型的RDD,可按key分组按val做聚合
- 第四个算子:mapValues算子, 只针对map中value进行计算的
- 回顾WordCount中的算子
- 第五个算子: groupBy算子
- 第六个算子:Filter 过滤数据
- 第七个算子: distinct 去重
- 第八个算子: union 合并,不会去重
- 第九个算子: join 两个RDD算子内/外连接
- 第十个算子: intersection 求两个rdd的交集
- 第十一个算子: glom 按分区给数据加上嵌套
- 第十二个算子: groupByKey 针对KV自动按照key分组
- 第十三个算子: sortBy算子, 对rdd排序
- 第十四个算子: sortByKey算子, 对KV类型的key进行排序
- 案列
RDD算子
分布式对象的方法就是算子;
本地对象的方法叫函数或者方法
- 转换算子: 转换完还是RDD对象,比如map, flatMap等
- 行为算子: 转换完不是RDD对象,比如rdd.collect()是一个list对象
第一个算子: map算子
-> rdd.map(func) 作用是将RDD的数据一条条的处理,基于func函数返回新的RDD
func是一个函数 lanbda 也可以
rdd=sc.parallelize([1,2,3,4,5,6])
def mul(data):
return data*100
#方式1 lambda适合一行表达式
print(rdd.map(lambda x:x*100).collect())
#也可以返回一个元组
print(rdd.map(lambda x:(2,x*100)).collect())
#方式2 方法可以写多行进行复杂的运算
print(rdd.map(mul).collect())
[100, 200, 300, 400, 500, 600]
[(2, 100), (2, 200), (2, 300), (2, 400), (2, 500), (2, 600)]
[100, 200, 300, 400, 500, 600]
第二个算子: flatMap算子
作用是:解除嵌套 ; 二维数组变一维数组
rdd=sc.parallelize(["hadoop spark hadoop ","flink spark hadoop ","hadoop spark flink "])
print("map的结果是二维数组:",rdd.map(lambda x:x.split(" ")).collect())
print("flatMap直接是一维数组(解除嵌套):",rdd.flatMap(lambda x:x.split(" ")).collect())
map的结果是二维数组: [['hadoop', 'spark', 'hadoop', ''], ['flink', 'spark', 'hadoop', ''], ['hadoop', 'spark', 'flink', '']]
flatMap直接是一维数组(解除嵌套): ['hadoop', 'spark', 'hadoop', '', 'flink', 'spark', 'hadoop', '', 'hadoop', 'spark', 'flink', '']
第三个算子:reduceByKey算子, 针对KV型的RDD,可按key分组按val做聚合
rdd.reduceByKey(func)
func:(V,V) ->V 两个入参类型一直,返回的值的类型也一致
rdd=sc.parallelize([('a',1),('a',2),('a',3),('c',1),('c',1),('b',2),('b',1),('d',10)])
#写函数是为了打印a,b的值,看看a,b的计算流程
def mByKeyPara(a,b):
# print(a,b)
return a+b
# 相当于sum求和; #理解里面(a+b)的运算逻辑
print(rdd.reduceByKey(mByKeyPara).collect())
#同
print(rdd.reduceByKey(lambda a,b:a+b).collect())
[('c', 2), ('b', 3), ('d', 10), ('a', 6)]
[('c', 3), ('b', 6), ('d', 10), ('a', 20)]
第四个算子:mapValues算子, 只针对map中value进行计算的
rdd=sc.parallelize([('a',2),('a',3),('c',5),('b',8),('d',10)])
# 使用map也可以实现, 看着复杂,可以改成mapValues
print(rdd.map(lambda x:(x[0],x[1]*10)).collect())
#mapValues只针对二元组中的val计算
print(rdd.mapValues(lambda x:x*10).collect())
[('a', 20), ('a', 30), ('c', 50), ('b', 80), ('d', 100)]
[('a', 20), ('a', 30), ('c', 50), ('b', 80), ('d', 100)]
回顾WordCount中的算子
file_rdd = sc.textFile("/word.txt")
print("\n文件内容:\n",file_rdd.collect())
#将单词进行切割, flatMap直接就是一维数组
words_rdd=file_rdd.flatMap(lambda line: line.split(" "))
print("\n将单词进行切割:\n",words_rdd.collect())
# 将单词转换为元组形象, key是单词,value是1
words_with_one_rdd = words_rdd.map(lambda x: (x,1))
print("\n将单词转换为元组形象:\n",words_with_one_rdd.collect())
# 将元组的value 按照key来分组
result_rdd = words_with_one_rdd.reduceByKey(lambda a,b: a + b)
print("\n将元组的value 按照key来分组:\n",result_rdd.collect())
文件内容:
['itheima itcast itheima itcast', 'hadoop hdfs hadoop hdfs', 'hadoop mapreduce hadoop yarn', 'itheima hadoop itcast hadoop', 'itheima itcast hadoop yarn mapreduce', '', '']
将单词进行切割:
['itheima', 'itcast', 'itheima', 'itcast', 'hadoop', 'hdfs', 'hadoop', 'hdfs', 'hadoop', 'mapreduce', 'hadoop', 'yarn', 'itheima', 'hadoop', 'itcast', 'hadoop', 'itheima', 'itcast', 'hadoop', 'yarn', 'mapreduce', '', '']
将单词转换为元组形象:
[('itheima', 1), ('itcast', 1), ('itheima', 1), ('itcast', 1), ('hadoop', 1), ('hdfs', 1), ('hadoop', 1), ('hdfs', 1), ('hadoop', 1), ('mapreduce', 1), ('hadoop', 1), ('yarn', 1), ('itheima', 1), ('hadoop', 1), ('itcast', 1), ('hadoop', 1), ('itheima', 1), ('itcast', 1), ('hadoop', 1), ('yarn', 1), ('mapreduce', 1), ('', 1), ('', 1)]
将元组的value 按照key来分组:
[('itcast', 4), ('hadoop', 7), ('hdfs', 2), ('yarn', 2), ('', 2), ('itheima', 4), ('mapreduce', 2)]
第五个算子: groupBy算子
功能:将rdd的数据分组
语法: rdd.groupBy(func)
func:(T) -> K 传入一个值,返回值无所谓; 返回的值就是分组的
rdd=sc.parallelize([('a',1),('a',2),('a',3),('c',1),('c',1)])
# t[0] 是按照key分组, 也可以按照value分组, 同样也可以定制分组,写方法,比如奇偶数
groupRdd=rdd.groupBy(lambda t:t[0])
groupRddList=groupRdd.map(lambda t:(t[0],list(t[1])))
print(groupRddList.collect())
[('c', [('c', 1), ('c', 1)]), ('a', [('a', 1), ('a', 2), ('a', 3)])]
留下疑问:分组之后,怎么求和/最大/最小值/平均值/计数?
第六个算子:Filter 过滤数据
功能: 过滤符合条件的数据
filter(func)
func(x) -> boolean
rdd=sc.parallelize([1,2,3,4,5,6])
rdd.filter(lambda x:x%2==1).collect()
[1, 3, 5]
第七个算子: distinct 去重
# 单值去重
rdd=sc.parallelize([1,2,1,1,2,3,3,3,2,4,16])
print(rdd.distinct().collect())
#元组也可以去重
rdd2=sc.parallelize([('a',1),('a',2),('c',1),('c',1)])
print(rdd2.distinct().collect())
[2, 4, 16, 1, 3]
[('a', 1), ('a', 2), ('c', 1)]
第八个算子: union 合并,不会去重
rdd1=sc.parallelize([1,2,1,1,2,3,3,3,2,4,16])
rdd2=sc.parallelize([100,200])
#只合并,不会去重
print(rdd1.union(rdd2).collect())
#手动调用distinct()去重
print(rdd1.union(rdd2).distinct().collect())
[1, 2, 1, 1, 2, 3, 3, 3, 2, 4, 16, 100, 200]
[4, 16, 100, 200, 1, 2, 3]
第九个算子: join 两个RDD算子内/外连接
#部门ID和员工姓名
x = sc.parallelize([(1001,"zhangsan"),(1002,"isi"),(1003,"wangwu"),(1004,"zhangliu")])
# 部门ID和部门名称
y = sc.parallelize([(1001,"销售部"),(1002,"教育部")])
# join是内连接,按照key进行关联
print(x.join(y).collect())
# 左连接
print(x.leftOuterJoin(y).collect())
# 右连接
print(x.rightOuterJoin(y).collect())
[(1001, ('zhangsan', '销售部')), (1002, ('isi', '教育部'))]
[(1004, ('zhangliu', None)), (1001, ('zhangsan', '销售部')), (1002, ('isi', '教育部')), (1003, ('wangwu', None))]
[(1001, ('zhangsan', '销售部')), (1002, ('isi', '教育部'))]
第十个算子: intersection 求两个rdd的交集
rdd1 = sc.parallelize([('a',1),('b',1),('c',1)])
rdd2 = sc.parallelize([('a',1),('c',1)])
inter_rdd=rdd1.intersection(rdd2)
print(inter_rdd.collect())
[('a', 1), ('c', 1)]
第十一个算子: glom 按分区给数据加上嵌套
功能:将RDD的数据加上嵌套,这个嵌套按照分区来进行,比如RDD数据[1,2,3,4,5] 有2个分区那么,被glom后,数据变成: [ [1,2,3],[4,5] ]
使用方法:
rdd .glom()
rdd=sc.parallelize([1,2,3,4,5,6,7])
print(rdd.glom().collect())
[[1, 2, 3], [4, 5, 6, 7]]
第十二个算子: groupByKey 针对KV自动按照key分组
rdd = sc.parallelize([('a',1),('a',1),('b',1),('b',1),('b',1)])
grouped_rdd = rdd.groupByKey()
print(grouped_rdd.map(lambda x: (x[0],list(x[1]))).collect())
[('b', [1, 1, 1]), ('a', [1, 1])]
第十三个算子: sortBy算子, 对rdd排序
语法: rdd.sortBy(func,ascending=False, numPartitions=1)
- func: (T) U: 告知按照dd中的哪个数据进行排序,比如 lambda x: [1] 表按照rdd中的第二列元素进行排序
- ascending True升序 False 降序
- numPartitions: 用多少分区排序
rdd=sc.parallelize([9,5,6,7,1,2,3,4])
print(rdd.sortBy(lambda x:x).collect())
rdd=sc.parallelize([1,2,1,1,2,3,3,3,2,4,16])
print(rdd.sortBy(lambda x:x).collect())
rdd=sc.parallelize([('a',32),('a',21),('a',73),('c',31),('c',10)])
print(rdd.sortBy(lambda x:x[1]).collect())
[1, 2, 3, 4, 5, 6, 7, 9]
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 16]
[('c', 10), ('a', 21), ('c', 31), ('a', 32), ('a', 73)]
第十四个算子: sortByKey算子, 对KV类型的key进行排序
rdd=sc.parallelize([('a',32),('c',31),('a',21),('a',73),('c',10)])
#默认按照key排序
print(rdd.sortByKey(ascending=False).collect())
[('c', 31), ('c', 10), ('a', 32), ('a', 21), ('a', 73)]
案列
需求:
读取data文件夹中的 order.text文件,提取北京的数据,组合北京和商品类别进行输出
数据格式
{“id”:1,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“平板电脑”,“areaName”:“北京”,“money”:“1450”}|{“id”:2,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“手机”,“areaName”:“北京”,“money”:“1450”}|{“id”:3,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“手机”,“areaName”:“北京”,“money”:“8412”}
{“id”:4,“timestamp”:“2019-05-08T05:01.00Z”,“category”:“电脑”,“areaName”:“上海”,“money”:“1513”}|{“id”:5,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“家电”,“areaName”:“北京”,“money”:“1550”}|{“id”:6,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“电脑”,“areaName”:“杭州”,“money”:“1550”}
{“id”:7,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“电脑”,“areaName”:“北京”,“money”:“5611”}|{“id”:8,“timestamp”:“2019-05-08T03:01.00Z”,“category”:“家电”,“areaName”:“北京”,“money”:“4410”}|{“id”:9,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“家具”,“areaName”:“郑州”,“money”:“1120”}
{“id”:10,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“家具”,“areaName”:“北京”,“money”:“6661”}|{“id”:11,“timestamp”:“2019-05-08T05:03.00Z”,“category”:“家具”,“areaName”:“杭州”,“money”:“1230”}|{“id”:12,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“书籍”,“areaName”:“北京”,“money”:“5550”}
{“id”:13,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“书籍”,“areaName”:“北京”,“money”:“5550”}|{“id”:14,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“电脑”,“areaName”:“北京”,“money”:“1261”}|{“id”:15,“timestamp”:“2019-05-08T03:03.00Z”,“category”:“电脑”,“areaName”:“杭州”,“money”:“6660”}
{“id”:16,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“电脑”,“areaName”:“天津”,“money”:“6660”}|{“id”:17,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“书籍”,“areaName”:“北京”,“money”:“9000”}|{“id”:18,“timestamp”:“2019-05-08T05:01.00Z”,“category”:“书籍”,“areaName”:“北京”,“money”:“1230”}
{“id”:19,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“电脑”,“areaName”:“杭州”,“money”:“5551”}|{“id”:20,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“电脑”,“areaName”:“北京”,“money”:“2450”}
{“id”:21,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“食品”,“areaName”:“北京”,“money”:“5520”}|{“id”:22,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“食品”,“areaName”:“北京”,“money”:“6650”}
{“id”:23,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“服饰”,“areaName”:“杭州”,“money”:“1240”}|{“id”:24,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“食品”,“areaName”:“天津”,“money”:“5600”}
{“id”:25,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“食品”,“areaName”:“北京”,“money”:“7801”}|{“id”:26,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“服饰”,“areaName”:“北京”,“money”:“9000”}
{“id”:27,“timestamp”:“2019-05-08T01:03.00Z”,“category”:“服饰”,“areaName”:“杭州”,“money”:“5600”}|{“id”:28,“timestamp”:“2019-05-08T01:01.00Z”,“category”:“食品”,“areaName”:“北京”,“money”:“8000”}|{“id”:29,“timestamp”:“2019-05-08T02:03.00Z”,“category”:“服饰”,“areaName”:“杭州”,“money”:“7000”}
import json
#1.读取文件
rdd = sc.textFile("/order.txt")
# 2.将每条json数据取出
json_str_rdd = rdd.flatMap(lambda x: x.split("|") )
# 3.将每个json字符串,变成字典对象
json_dict_rdd = json_str_rdd.map(lambda x: json.loads(x) )
# 4.过滤数据,只保留北京
beijing_rdd = json_dict_rdd.filter(lambda x: x['areaName']=="北京")
# 5.组合北京 和 商品类型
combine_rdd = beijing_rdd.map(lambda x: x['areaName'] + ""+ x['category'])
# 6.去重,并且输出
print(combine_rdd.distinct().collect())
['北京平板电脑', '北京家电', '北京家具', '北京书籍', '北京手机', '北京电脑', '北京食品', '北京服饰']