1.从已经存在集合
2.已经存在外部数据源
3.从已经存在rdd转换成一个新的rdd
常用转换算子
transformation
map、flatmap、fillter、mappartitions、distinct
groupby、sortby、reducebykey、mapvalues
actions: toreach/foreachpartition
转换算子和行动算子区别:
转换算子返回一个数据集而行动算子返回一个具体值,如reduce算子是行动算子 而 reducebykey是转换算子
action算子会触发job执行
懒加载:不会立即执行 不会触发job
过程
1. 条件表达式A1 = A.filter(Column condition)
2. 自定义过滤函数A1 = A.filter(FilterFunction
3. 条件字符串A1 = A.filter(String condition)
命令
val data = sc.parallelize(List(10,20,35,40))
val filterfunc = data.filter(x => x!=20).collect、
//结果:Array[Int] = Array(10, 35, 40)
一一映射 处理rdd里面每一个元素
1.使用并行化集合创建RDD。
val data = sc.parallelize(List(10,20,30))
2.应用map函数并传递执行所需的表达式。
val mapfunc = data.map(x => x+10)
//结果:Array[Int] = Array(20, 30, 40)
代码
val rdd = sc.parallelize(List(1, 2, 3, 4))
rdd.print(0)
//3 1 4 2
val rdd2 = sc.makeRDD(List(1, 2, 3, 4))
rdd2.print(0)
//1 2 3 4
map和mapPartitions
map每个一元素作用一个函数或者是算子
mapPartitions:有几个调用几次
可以查看每个分区对应的数据
代码
rdd.mapPartitionsWithIndex((index,partition)=>{
partition.map(x=> s"分区的下标${index},分区的元素$x")
}).print(0)
//分区的下标0,分区的元素1
//分区的下标1,分区的元素3
//分区的下标0,分区的元素2
//分区的下标1,分区的元素4
针对kv类型进行操作 对v进行处理
rdd.map(x=>(x,1)).mapValues(x=>x+1).print(0)
//(3,2)
//(1,2)
//(4,2)
//(2,2)
一一映射(压扁的)
flatmap = flatten + map
举例:sc.parallelize(List(List(1,2),List(3,4))).collect
sc.parallelize(List(List(1,2),List(3,4))).map(x=> x.map(_*2)).collect
sc.parallelize(List(List(1,2),List(3,4))).flatMap(x=>x.map(_*2)).collect
sc.parallelize(List(List(1,2),List(3,4))).flatMap(x=>x.map(_*2)).print(0)
把每一个分区的数据形成数组
三个参数
withReplacement:表示抽出样本后是否在放回去,true表示会放回去,这也就意味着抽出的样本可能有重复
fraction:这是一个double类型的参数,0-1之间,eg:0.3表示抽出30%
如果抽取不放回的场合:则表示数据源中每条数据被抽取的概率,
如果抽取放回的场合:表示数据源中的每条数据被抽取的可能次数
seed:抽取数据时随机算法的种子,如果传递参数,则运行时每次抽取的数据是一样的,如果不传递参数,则每次运行时结果是不一样的。【一般无用】
sc.parallelize(1 to 20).sample(false,0.4,20).print(0)
//11 5 14 15 17 19
rdd1.union(rdd2)
scval rdd1 = sc.parallelize(1 to 3)
val rdd2 = sc.parallelize(2 to 5)
val rdd3 = rdd1.union(rdd2)
rdd3.print(0)
//结果 1 2 3 2 3 4 5
val rdd1 = sc.parallelize(1 to 3)
val rdd2 = sc.parallelize(2 to 5)
rdd1.intersection(rdd2).print(0)
//结果 2 3
val rdd1 = sc.parallelize(1 to 3)
val rdd2 = sc.parallelize(2 to 5)
rdd1.intersection(rdd2).print(1)
//结果 1
默认采用分区器:hash
元素 % 分区数 (List(4,4,4,5,5,5,6,6,6,7,8,9,10,10)
分区号:0 、元素是4、8 【4 % 4 == 0】
分区号:1 元素是5 、9
分区号:2 元素是6、10
分区号:3 元素是7
代码
val a = sc.parallelize(List(4,4,4,5,5,5,6,6,6,7,8,9,10,10))
a.distinct().print(0)
//7 9 5 4 6 8 10
a.distinct(4).mapPartitionsWithIndex((index,partition)=>{
partition.map(x=> s"分区号:${index},元素是${x}")
}).print(0)
//分区号:1,元素是9
//分区号:0,元素是4
//分区号:1,元素是5
//分区号:0,元素是8
//分区号:3,元素是7
//分区号:2,元素是6
//分区号:2,元素是10
效率低、不灵活
过程
按Key进行分组,List(("A",1),("B",2),("A",2),("B",3))
(B,(2, 3)) (A,(1, 2))
然后对key进行个数统计
# (A,2) # (B,2)
代码
val arr7 = List(("A",1),("B",2),("A",2),("B",3))
val rdd33 = sc.parallelize(arr7)
val groupByKeyRDD = rdd33.groupByKey()
groupByKeyRDD.foreach(println)
//(A,CompactBuffer(1, 2))
//(B,CompactBuffer(2, 3))
减少map端输出的数据量
仅对加和操作使用,无法对平均值使用
mapreduce
input map [combine] reduce output
过程
map
(a,1) (a,1) (a,1) (b,1) (b,1)
combine:顶聚合 按照map端输出的key进行聚合数据
(a,3)
(b,2)
reduce
a,<1,1,1>
a,<1,1,1>
val rdd6 = sc.parallelize(List("a", "a", "a", "a", "b", "b", "b"))
rdd6.groupBy(x => x).print(0)
// (b,CompactBuffer(b, b, b))
// (a,CompactBuffer(a, a, a, a))
val wc = sc.parallelize(List(("a", 1), ("a", 2), ("b", 2), ("c", 3)))
wc.groupBy(x => x._1).print(0)
//(b,CompactBuffer((b,2)))
//(a,CompactBuffer((a,1), (a,2)))
//(c,CompactBuffer((c,3)))
mapSideCombine = true+ func
distinct底层
map + reduceByKey + map 对key进行去重
val rdd5 = sc.parallelize(List(("tiantian", 15), ("luo", 18), ("lili", 12)))
rdd5.sortByKey().print(0)
rdd5.map(x => (x._2,x._1)).sortByKey(false).map(x => (x._2,x._1)).print(0)
/**
* (lili,12)
* (tiantian,15)
* (luo,18)
* --------
* (luo,18)
* (tiantian,15)
* (lili,12)
*/
val rdd5 = sc.parallelize(List(("tiantian", 15), ("luo", 18), ("lili", 12)),1)
rdd5.sortBy(x => x._2, false).print(0)
/**
* (luo,18)
* (tiantian,15)
* (lili,12)
*/
(List(("tiantian", 15), ("luo", 18), ("lili", 12)),1) 中的1:定义一个分区块
join和 cogroup
1.根据 key进行关联
2. join返回值类型:
val t1 = sc.parallelize(List(("tiantian", 15), ("luo", 18), ("lili", 12)))
val t2 = sc.parallelize(List(("tiantian", "辽宁"), ("luo", "内蒙"), ("lili", "广西")))
t1.join(t2).print(0)
/**结果
* (tiantian,(15,辽宁))
* (luo,(18,内蒙))
* (lili,(12,广西))
*/
val t1 = sc.parallelize(List(("tiantian", 15), ("luo", 18), ("lili", 12)))
val t2 = sc.parallelize(List(("tiantian", "辽宁"), ("luo", "内蒙"), ("lili", "广西")))
t1.cogroup(t2).print(0)
/**结果
* (tiantian,(CompactBuffer(15),CompactBuffer(辽宁)))
* (luo,(CompactBuffer(18),CompactBuffer(内蒙)))
* (lili,(CompactBuffer(12),CompactBuffer(广西)))
*/
触发作业的执行
好处:更高效
1.collect()
2.foreach()
1.控制台
2.hdfs
3.db
3.foreachpartition()
4.reduce()
5.first() take()
first底层调用take算子
6.top
7.countbukey
要求:按照商品的价格进行【desc】排序 如果价格相同 按照库存排序【asc】
数据
商品名字 商品价格 库存数量
dior 300 1000
香奈儿 4000 2
螺蛳粉 20098
3090显卡200 10
代码
def main(args: Array[String]): Unit = {
val sc: SparkContext = ContextUtils.getSparkContext(this.getClass.getSimpleName)
import org.example.sparkcore.function.ImplictAsRdd._
val input = sc.parallelize(List("dior 300 1000", "YSL 350 500", "纪梵希 280 23"),1)
val etlData: RDD[(String, Int, String)] = input.map(line => {
val strings = line.split("\t")
val name = strings(0)
val price = strings(1).toInt
val cnt = strings(2)
(name, price, cnt)
})
etlData.sortBy(x => (-x._2,x._3)).print(0)
sc.stop()
}
//出错了 数组越界
1
def main(args: Array[String]): Unit = {
val sc: SparkContext = ContextUtils.getSparkContext(this.getClass.getSimpleName)
import org.example.sparkcore.function.ImplictAsRdd._
val Data = sc.parallelize(List("a,5,2", "b ,2,3", "c,3,8","a,1,99","b,8,2"))
val eltData: RDD[(String,(Int,Int))] = Data.map(Line => {
val strings = Line.split(",")
val word: String = strings(0)
val show = strings(1).toInt
val click= strings(2).toInt
(word,(show,click))
})
eltData.reduceByKey((x,y)=>{
(x._1 + y._1, x._2 + y._2)
}).print(0)
sc.stop()
}
//(b,(8,2))
//(a,(6,101))
//(b ,(2,3))
//(c,(3,8))