Spark Key-Value类型

1) groupByKey案例
1.作用:groupByKey 对每一个进行操作,但只生成一个sequence
2.需求: 创建一个pairRDD,将相同key对应值聚合到一个sequence中,并计算相同对应值的相加结果

//创建一个RDD算子,指定分区数2
val ListRDD: RDD[String] = sc.makeRDD(List("Abo", "Spark", "Hadoop",
      "Python", "Python", "Scala", "Spark", "Spark"), 2)
//转换结构将ListRDD集合中每一个元素映射成二元组("Abo",1)形式
    val MapRDD: RDD[(String, Int)] = ListRDD.map((_, 1))
    //将上述MapRDD集合中的元素排序(二元组第一个元素为Key)
    val GroupByKeyRDD: RDD[(String, Iterable[Int])] = MapRDD.groupByKey()

返回结果:
(Python,CompactBuffer(1, 1))
(Scala,CompactBuffer(1))
(Abo,CompactBuffer(1))
(Spark,CompactBuffer(1, 1, 1))
(Hadoop,CompactBuffer(1))
上一步的基础上对相同key的value值进行求和

 val groupBySum: RDD[(String, Int)] = GroupByKeyRDD.map(x => (x._1, x._2.sum))
 groupBySum.collect().foreach(println)

(Python,2)
(Scala,1)
(Abo,1)
(Spark,3)
(Hadoop,1)

2) reduceByKey(func,[numTasks]) 案例
1.在一个(K,V) 的RDD上调用,返回一个(K,V)的RDD,使用指定的reduce函数,将相同的key值聚合到一起,reduce任务可以通过可选参数numTasks来进行设置
2.需求,创建一个pairRDD,计算相同key对应值的相加结果

 val ListRDD: RDD[(String, Int)] = sc.makeRDD(List(("Abo", 1), ("Spark", 1), ("Hadoop", 1),
      ("Python", 1), ("Python", 1), ("Scala", 1), ("Spark", 1), ("Spark", 1)), 2)
      //计算相同key对应值的相加结果
    val reduceByKeyRDD: RDD[(String, Int)] = ListRDD.reduceByKey(_ + _)

返回结果:
(Python,4)
(Scala,2)
(Abo,3)
(Spark,4)
(Hadoop,1)
reduceByKey和groupByKey的区别
1.reduceByKey: 按照key进行聚合,在shuffle之间有combine(预聚合)操作,返回结果是RDD[k,v]
2.groupByKey:按照key进行分组,直接进行shuffle.
3.开发中自然是建议reduceByKey
3) aggregateByKey案例
参数:(zeroValue: U, partitioner: Partitioner)(seqOp: (U, V) => U,
combOp: (U, U) => U)
1.作用: 在kv对的RDD中,按Key将value进行分组合并,合并时,将每个value和初始值seq函数的参数,进行计算,返回的结果作为一个新的kv对,然后再将结果按照key进行合并,最后将每个分组的value传递给combin函数进行计算(先将前两个value进行计算,将返回结果和下一个value传给combin函数,依次类推),将key于计算结果作为一个新的kv对输出
2.参数描述:
(1) zeroValue: 给每一个分区中的每一个key一个初始值
(2) seqOp: 函数用于在每一个分区中用初始值逐步迭代value
(3) combOp: 函数用于合并每个分区中的结果
3.需求: 创建一个pariRDD,取出每个分区相同key对应值的最大值,然后相加.

val ListRDD: RDD[(String, Int)] = sc.makeRDD(Array(("a", 3), ("c", 3), ("c", 6), ("a", 4), ("a", 7), ("b", 10)), 2)
ListRDD.glom.collect().foreach(data => println(data.mkString(",")))
println("-----------------------")
//分区内相同key求最大值,分区间求和
//  def aggregateByKey[U: ClassTag](zeroValue: U, partitioner: Partitioner)(seqOp: (U, V) => U,
//      combOp: (U, U) => U): RDD[(K, U)] = self.withScope {
    
    
//zeroValue:初始值, (seqOp: (U, V) => U:分区内   combOp: (U, U) => U)分区间
val aggRDD: RDD[(String, Int)] = ListRDD.aggregateByKey(0)(math.max(_, _), _ + _)
    val aggRDD: RDD[(String, Int)] = ListRDD.aggregateByKey(0)(math.max(_, _), _ + _)
    aggRDD.glom().collect().foreach(println)

(a,3),(c,3),(c,6)
(a,4),(a,7),(b,10)


(b,10)
(a,10),(c,6)

4) foldByKey案例
(zeroValue: V)(func: (V, V) => V)
aggregateByKey算子(seqOp: (U, V) => U,
combOp: (U, U) => U)这两个参数在foldByKey视为一个参数,即只能完成一个操作,分区中与合并每个分区所作的操作相同.

val foldRDD: RDD[(String, Int)] = ListRDD.foldByKey(0)(_ + _)
    foldRDD.glom().collect().foreach(data=>println(data.mkString(",")))

返回结果:
(a,3),(c,3),(c,6)
(a,4),(a,7),(b,10)


(b,10)
(a,14),(c,9)

  1. combineByKey 案例
    这个算子还是比较复杂的
    createCombiner: V => C,
    mergeValue: (C, V) => C,
    mergeCombiners: (C, C) => C)
    createCombiner:组合器函数,用于将V类型转换成C类型,输入参数为RDD[K,V]中的V,输出为C(分区内每种key调用一次)
    mergeValue:合并值函数,将一个C类型和一个V类型值合并成一个C类型,输入参数为(C,V),输出为C(分区内将createCombiner()结果与相同的key对应的值做合并)
    mergeCombiners:合并组合器函数,用于将两个C类型值合并成一个C类型,输入参数为(C,C),输出为C(将各个分区间相同的key对应的结果做聚合)

需求: 创建一个pairRDD,根据key计算每种key的均值.(先计算每个key出现的次数以及可以对应值的总和,在相除得到结果)

val ListRDD: RDD[(String, Int)] = sc.makeRDD(Array(("c", 10), ("c", 20), ("a",4), ("c", 10),("a", 7),("b",20),("a",28)), 2)
    ListRDD.glom.collect().foreach(data => println(data.mkString(",")))
    println("*" * 30)
    //求ListRDD中的每一个key出现的次数,以及key对应value值的总和
    val combineRDD: RDD[(String, (Int, Int))] = ListRDD.combineByKey((_, 1),
      (sum1: (Int, Int), v) => (sum1._1 + v, sum1._2 + 1),
      (sum2: (Int, Int), sum3: (Int, Int)) => (sum2._1 + sum3._1, sum2._2 + sum3._2))
  val resultRDD: RDD[(String, Double)] = combineRDD.map(data => (data._1, data._2._1 / data._2._2.toDouble))
    resultRDD.glom().collect().foreach(data=>println(data.mkString(",")))

createCombiner: V => C (_, 1): 将key对应的值映射成一个二元组(“c”,10)=>(10,1)
mergeValue: (C, V) => C (sum1: (Int, Int), v) => (sum1._1 + v, sum1._2 + 1) 元组的第一位与v相加,元组第二位自增1 (10,1) 20==》(30,2)

mergeCombiners: (C, C) => C (sum2: (Int, Int), sum3: (Int, Int)) 元组的第一位与第二位分别累加 (30,2) (10,1) ==>(40,3)
运行结果:
(c,10),(c,20),(a,4)
(c,10),(a,7),(b,20),(a,28)


(b,20.0)
(a,13.0),(c,13.333333333333334)

猜你喜欢

转载自blog.csdn.net/changshupx/article/details/108509295