速查表
- 键值对数据类型支持算子
类别 | 算子 |
---|---|
聚合操作 | reduceByKey;foldByKey;combineByKey |
分组操作 | cogroup,groupByKey |
连接操作 | join;leftOuterJoin;rightOuterJoin |
排序操作 | sortBy;sortByKey |
Action | countByKey;take;collect |
- 数字型数据支持算子
算子 | 含义 |
---|---|
count | 个数 |
mean | 均值 |
sum | 求和 |
max | 最大值 |
min | 最小值 |
variance | 方差 |
sampleVariance | 从采样中计算方差 |
stdev | 标准差 |
sampleStdev | 采样的标准差 |
目录标题
- Transformations算子(惰性的)
- Action算子
Transformations算子(惰性的)
map
map是针对分区内的每一条数据进行处理rdd.map(item=>(对item做一条数据处理逻辑))
mapPartitions(List[T]->List[U])
1.使用场景
和map类似,但是针对整个分区的数据转换,map的粒度是条数,而mapPartitions粒度是分区数
- map的func参数是单条数据,mapPartitions的func参数是一个集合(一个分区整个所有的数据)
- map的func返回值也是单条数据,mapPartition的func返回值是一个集合
2.示例
import org.apache.spark.{SparkConf, SparkContext}
import org.junit.Test
class TransformationOp {
private val conf: SparkConf = new SparkConf().setMaster("local").setAppName("")
private val sc = new SparkContext(conf)
@Test
def mapParttitions: Unit ={
//1.数据生成
val rdd = sc.parallelize(List(1,2,3,4,5,6),2)
//2.算子使用
.mapPartitions(iter=>{
iter.foreach(item => println(item))
iter
})
.collect()
.foreach(item=>println(item))
}
mapPartitionsWithIndex
1.使用场景
和mapPartitions类似,只是在函数中增加了分区的Index
2.示例
import org.apache.spark.{SparkConf, SparkContext}
import org.junit.Test
class TransformationOp {
private val conf: SparkConf = new SparkConf().setMaster("local").setAppName("")
private val sc = new SparkContext(conf)
@Test
def mapPartitionsWitIndex: Unit ={
val rdd = sc.parallelize(List(1,2,3,4,5,6),2)
.mapPartitionsWithIndex((index,iter)=>{
println("index:"+index)
iter.foreach(item=>println(item))
iter
})
.collect()
}
}
mapValues
1.使用场景
MapValues 只能作用于 Key-Value 型数据, 和 Map 类似, 也是使用函数按照转换数据, 不同点是 MapValues 只转换 Key-Value 中的 Value
2.示例
sc.parallelize(Seq(("a", 1), ("b", 2), ("c", 3)))
.mapValues( value => value * 10 )
.collect()
Filter过滤
1.使用场景
Filter 算子的主要作用是过滤掉不需要的内容
2.示例
sc.parallelize(Seq(1, 2, 3))
.filter( value => value >= 2 )//只要大于2的数据
.collect()
sample抽样
1.使用场景
- Sample 算子可以从一个数据集中抽样出来一部分, 常用作于减小数据集以保证运行速度, 并且尽可能少规律的损失
- sample(withReplacement, fraction, seed)
- Sample 接受第一个参数为
withReplacement
为true表示有放回,false表示无放回 - Sample 接受第二个参数为
fraction
, 抽样比例 - Sample 接受第三个参数为
seed
, 随机数种子
2.示例
sc.parallelize(Seq(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
.sample(withReplacement = true, 0.6, 2)
.collect()
集合操作-并集union
val rdd1 = sc.parallelize(Seq(1, 2, 3))
val rdd2 = sc.parallelize(Seq(4, 5, 6))
rdd1.union(rdd2)
.collect()
集合操作-交集intersection
val rdd1 = sc.parallelize(Seq(1, 2, 3, 4, 5))
val rdd2 = sc.parallelize(Seq(4, 5, 6, 7, 8))
rdd1.intersection(rdd2)
.collect()
集合操作-插集subtract
1.使用场景
rdd1里面有的rdd2里面没有的
2.示例
val rdd1 = sc.parallelize(Seq(1, 2, 3, 4, 5))
val rdd2 = sc.parallelize(Seq(4, 5, 6, 7, 8))
rdd1.subtract(rdd2)
.collect()
reduceByKey
1.使用场景
- 聚合操作:ReduceByKey 只能作用于 Key-Value 型数据,所有先按照 Key 分组生成一个 Tuple, 然后针对每个组执行 reduce 算子
- def reduceByKey(func)
- func固定:((curr,agg)=>curr+agg)
2.示例
sc.parallelize(Seq(("a", 1), ("a", 1), ("b", 1)))
.reduceByKey( (curr, agg) => curr + agg )
.collect()
groupByKey
1.使用场景
GroupByKey 算子的主要作用是按照 Key 分组, 和 ReduceByKey 有点类似, 但是 GroupByKey 并不求聚合, 只是列举 Key 对应的所有 Value
2.示例
sc.parallelize(Seq(("a", 1), ("a", 1), ("b", 1)))
.groupByKey()
.collect()
combineByKey
使用场景
- 对数据集按照 Key 进行聚合
- combineByKey(createCombiner, mergeValue, mergeCombiners, [partitioner], [mapSideCombiner], [serializer])
- 参数:
createCombiner 将 Value 进行初步转换,就是把value值变为元组,赋予一个初始词频1,这个他只作用于第一条数据
mergeValue 在每个分区把上一步转换的结果,于未转化的结果聚合,每聚合一条词频加1最终得到分区结果
mergeCombiners 再把所有的分区结果基础上把相同k的分区结果的聚合得到我们的最终结果
后三个是有默认值的:
partitioner 分区方式
mapSideCombiner 控制是否在Map端进行Combine
serializer 序列化器
示例
val rdd = sc.parallelize(Seq(
("zhangsan", 99.0),
("zhangsan", 96.0),
("lisi", 97.0),
("lisi", 98.0),
("zhangsan", 97.0))
)
//求每个人的平均数(总分数/科目数)
val combineRdd = rdd.combineByKey(
createcombiner = score => (score, 1),
mergeValue = (scoreCount: (Double, Int),newScore) => (scoreCount._1 + newScore, scoreCount._2 + 1),
mergeCombines =
(scoreCount1: (Double, Int), scoreCount2: (Double, Int)) =>
(scoreCount1._1 + scoreCount2._1, scoreCount1._2 + scoreCount2._2)
) //scorecount1:是传入值curr,scorecount2是累加结果agg
//("张三",(99+96+97,3))
val meanRdd = combineRdd.map(score => (score._1, score._2._1 / score._2._2))
meanRdd.collect()
flodByKey
1.使用场景
他与reduceByKey逻辑相同,唯一不同是使用柯里化可以对初始值进行定义.他的初始值作用是对curr进行设置,设定5,curr就相应的加5
foldByKey(zeroValue)(func)
参数
zeroValue 初始值
func固定为: ((curr,age)=>curr+age)
2.示例
sc.parallelize(Seq(("a", 1), ("a", 1), ("b", 1)))
.foldByKey(zeroValue = 10)( (curr, agg) => curr + agg )
.collect()
aggregateByKey
1.使用场景
- 特别适合的场景是先处理后聚合
- rdd.aggregateByKey(zeroValue)(seqOp, combOp)
- 参数
zeroValue 指定初始值
seqOp (初始值,集合中的数值)=>方法体就是初始值和集合中的数据进行数学运行
comboOp 将seqOp处理过的结果进行聚合
2.示例
val rdd = sc.parallelize(Seq(("手机", 10.0), ("手机", 15.0), ("电脑", 20.0)))
val result = rdd.aggregateByKey(0.8)(
seqOp = (zero, price) => price * zero,
combOp = (curr, agg) => curr + agg
).collect()
println(result)
join
1.使用场景
将两个 RDD 按照相同的 Key 进行连接(两个rdd的k放入到一个元组中)
join(other, [partitioner or numPartitions])
2.示例
val rdd1 = sc.parallelize(Seq(("a", 1), ("a", 2), ("b", 1)))
val rdd2 = sc.parallelize(Seq(("a", 10), ("a", 11), ("a", 12)))
rdd1.join(rdd2).collect()
排序sortBy,sortBykey
1.使用场景
- sortBy(func, ascending, numPartitions)
- 参数
func
通过这个函数返回要排序的字段
以下有默认值:
ascending
是否升序
numPartitions
分区数 - 注意点
- 普通的 RDD 没有
sortByKey
, 只有 Key-Value 的 RDD 才有 sortBy
可以指定按照哪个字段来排序,sortByKey
直接按照 Key 来排序
- 普通的 RDD 没有
2.示例
val rdd1 = sc.parallelize(Seq(("a", 3), ("b", 2), ("c", 1)))
val sortByResult = rdd1.sortBy( item => item._2 ).collect() //指定字段
val sortByKeyResult = rdd1.sortByKey().collect()
println(sortByResult)
println(sortByKeyResult)
改变分区数:coalesce,repartitioin
1.使用场景
repartitioin(numPartitions)进行分区的时候默认是Shuffle的
coalesce(numPartitions, shuffle)进行分区的时候默认是不Shuffle的,默认不能增大分区数
对于coalesce(numPartitions, shuffle)如果新的分区数量比原分区数大, 必须 Shuffled, 否则重分区无效
2.示例
val rdd = sc.parallelize(Seq(("a", 3), ("b", 2), ("c", 1)))
val oldNum = rdd.partitions.length
val coalesceRdd = rdd.coalesce(4, shuffle = true)
val coalesceNum = coalesceRdd.partitions.length //partitions分区数
val repartitionRdd = rdd.repartition(4)
val repartitionNum = repartitionRdd.partitions.length
print(oldNum, coalesceNum, repartitionNum)
updateStateByKey
k不动,对value值进行实时累加
.updateStateByKey((currValues: Seq[Int], state: Option[Int]) => {
var count = currValues.sum[当前批次数据求和] + state.getOrElse(0)[前面所有批次数据结果值];
Some(count)
})
[1 currvalues.sum=6 存入 Opetin=6
2
3]
[1 currValues.sum=3+6=9 存入Option=9
1
1]
注意:使用此算子必须要进行checkpoint检查点设置
为什么设置checkpoint,当计算失败了,数据可以临时保存在检查点,下次计算可以续上.
Action算子
collect,first,take,takeSample获取数据
1.使用场景
- first()
返回第一个元素 - take(N)
返回前N个元素 - takeSample(withReplacement, num,send))
抽样采样获取数据
withReplacement
, true有放回,false无放回
num
, 取样几个
send
随机种子,可以不传 - collect
以数组的形式返回数据集中所有元素
2.示例
rdd1.first()
rdd1.take(10)
rdd1.takeSample(withRepacement=true,num=3)
rdd1.collect()
reduce()
1.使用场景
对整个结果集规约, 最终生成一条数据, 是整个数据集的汇总
reduce( (curr一整条数据, agg) ⇒ (“自定义”,curr的k值+agg的k值)) )
返回一个元组
2.reduceByKey和reduce有什么区别:
1.reduce是一个Action算子,reduceByKey是一个转换算子
2.reduceByKey本质上是先按照Key分组,然后把每组聚合
3.reduce是针对一整个数据集来进行聚合
4.reduceByKey是Shuffle操作,先通过Partitoner函数指定分区规则(ByKey指定键),对数据进行分区,在在分区内进行聚合,最后返回多个值
而reduce不涉及Shuffle操作,得到多个分区数据后,对其进行统一的聚合,最后返回一个元组值
3.示例
val rdd = sc.parallelize(Seq(("手机", 10.0), ("手机", 15.0), ("电脑", 20.0)))
val result = rdd.reduce((curr, agg) => ("总价", curr._2 + agg._2))
println(result)
foreach()
1.使用场景
foreach( T ⇒ … )遍历每一个元素
2.示例
val rdd = sc.parallelize(List(1,3,4))
sc.foreach(item=>println(item))
count(),countByKey()求数量
1.使用场景
主要用于:数据倾斜,如果要解决数据倾斜的问题,是不是要先知道谁倾斜,通过countByKey可以查看Key对应的数据总数,从而解决数据倾斜
- count()
返回集合中元素个数 - countByKey()
返回Map映射,求得整个数据集中 Key 以及对应 Key 出现的次数
2.示例
val rdd = sc.parallelize(Seq(("a",1),("a",1),("c",3),("d",4))
println(rdd.count())
println(rdd.countByCount())