葵花宝典--sparkRDD(一)

一、Transformation(转换算子)

1、value类型

1)、map:映射,将RDD的数据进行转换,比如对数据乘2、把数据转换为元组

2)、mapPartition:对分区内数据进行map,入参是可迭代的集合,对入参进行map操作

3)、mapPartitionWithIndex:带分区号的map操作,入参是分区号和可迭代的集合

map和mapPartition的区别

  1. map每次处理一条数据
  2. mapPartition是处理一个分区内的数据,只有当分区内的数据处理完毕,原始RDD数据才能释放;当内存足够时,可增加数据处理效率,否则可能导致OOM

4)、flatMap:把RDD中是数据扁平化处理

5)、glom:与flatMap对应,把分区内的数据转为一个集合

6)、groupBy:根据一定的规则进行分组

7)、filter:根据规则进行过滤,剔除返回false的数据

8)、sample:采样函数,入参withReplacement(是否放回)、fraction(因子,如果放回传抽取次数,不放回传抽取概率0到1)、seed(随机数生成器种子)

9)、distinct:去重,可以指定去重后的分区个数

10)、coalesce:重新分区(常用于缩减分区),可以指定是否进行shuffe

11)、repartition:重新分区(常用于增加分区),底层调用的是带shuffe的coalesce函数

12)、sortBy:排序,入参为排序字段,升降序排序(默认升序)

13)、pipe:执行脚本,保证脚本是正确的

    //建立配置文件对象
    val conf = new SparkConf().setMaster("local[*]").setAppName("MY")
    //创建sc对象
    val sc = new SparkContext(conf)

    val rdd: RDD[Int] = sc.makeRDD(1 to 4,2)
    //map 映射
    val mapRdd: RDD[Int] = rdd.map(_*2)

    //mapPartitions 分区内执行map
    val mpRdd: RDD[Int] = rdd.mapPartitions(data => data.map(_*2))

    //mapPartitionsWithIndex 带分区号的映射
    val mpiRdd: RDD[(Int, Int)] = rdd.mapPartitionsWithIndex((index, datas) => {
      datas.map((index, _))
    })

    //filter 过滤
    val filter: RDD[Int] = rdd.filter(_%2 == 0)

    val listRDD=sc.makeRDD(List(List(1,2),List(3,4),List(5,6),List(7)), 2)
    //flatMap 扁平化
    val flatMapRdd: RDD[Int] = listRDD.flatMap(data=>data)

    //golm 将分区内的数据合并成一个数组
    val glomRdd: RDD[Array[List[Int]]] = listRDD.glom()

    //groupBy 分组
    val groupByKeyRdd: RDD[(Int, Iterable[Int])] = flatMapRdd.groupBy(_%2)

    val rdd: RDD[Int] = sc.makeRDD(1 to 20,2)

    //sample 抽样函数 返回的是RDD
    val sampleRdd: RDD[Int] = rdd.sample(false,0.3)
    //takeSample 抽取指定个数 返回的是集合
    val sampleRDD1: Array[Int] = rdd.takeSample(false,2)

    //distinct 去重,可以指定去重后的分区个数
    val distinctRdd: RDD[Int] = rdd.distinct()

    //coalesce 重新分区 缩减分区
    val coalRdd: RDD[Int] = rdd.coalesce(1)

    //repartition 重新分区 增加分区
    val repartitionRdd: RDD[Int] = rdd.repartition(3)

    //sortBy 排序 入参:排序字段 排序规则 默认升序
    val sortRdd: RDD[Int] = rdd.sortBy(ele=>ele,false)

    //pipe 执行脚本
    val pipeRdd: RDD[String] = rdd.pipe("/1.sh")

wordCount简单版本和复炸版本:

    //建立配置文件对象
    val conf = new SparkConf().setMaster("local[*]").setAppName("MY")
    //创建sc对象
    val sc = new SparkContext(conf)

    val strList: List[String] = List("Hello Scala", "Hello Spark", "Hello World")
    val rdd = sc.makeRDD(strList)

    val rddWC: RDD[(String, Int)] = rdd.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).map {
      case (word, itera) => (word, itera.size)
    }
    rddWC.collect().foreach(println)

    println("==================================================================================")

    val rdd2: RDD[(String, Int)] = sc.makeRDD(List(("Hello Scala", 2), ("Hello Spark", 3), ("Hello World", 2)))
    val rdd1WC: RDD[(String, Int)] = rdd2.flatMap {
      case (words, count) => words.split(" ").map(word => (word, count))
    }.groupBy(_._1).map {
      case (word, counts) => (word, counts.map(_._2).sum)
    }
    rdd1WC.collect().foreach(println)

2、双value类型

    val rdd1: RDD[Int] = sc.makeRDD(List(1,2,3,4,5,6))
    val rdd2: RDD[Int] = sc.makeRDD(List(,4,5,6,7,8,9))

    //union   合集
    val unionRdd: RDD[Int] = rdd1.union(rdd2)

    //intersection 交集
    val intersectionRdd: RDD[Int] = rdd1.intersection(rdd2)

    //subtract 差集 分区数相同并且分区内数据个数相同,否则会抛异常
    val subRdd: RDD[Int] = rdd1.subtract(rdd2)

    //拉链  分区数相同并且分区内数据个数相同,否则会抛异常
    val zip: RDD[(Int, Int)] = rdd1.zip(rdd2)

3、key-value类型

1)、partitionBy:指定分区类型,可以自定义,进行重新分区

2)、reduceByKey:根据key进行聚合,入参代表分区和分区间的计算函数

3)、groupByKey:根据key把value进行组合,把value组成一个集合

reduceByKey和groupByKey的区别:

  • reduceByKey有combiner,本地先聚合,再分区聚合
  • groupByKey是直接进行shuffe,在不影响业务的前提下使用reduceByKey效率较高

4)、aggregateByKey:指定初始值,分区函数和分区间函数不一致

5)、foldByKey:指定初始值,分区内和分区间计算函数相同

6)、combineByKey:根据key聚合,入参分别为:规定value的格式、value累加的函数、分区间的数据聚合函数

注:reduceByKey、aggregateByKey、foldByKey、combineByKey,底层调用combineByKeyWithClassTag函数,这4个聚合函数,只是是否有初始值、分区计算函数和分区间计算函数是否相同

7)、sortByKey:按照key排序,默认升序排序,key需要实现Ordered接口

8)、mapValues:只对value进行函数操作

9)、join:两个RDD的相连,类似sql,也具有左连接、右连接、全连接等算子

10)、cogroup:对本RDD的本身先进行聚合,再进行合并

object KVTransformationRDD1 {

  def main(args: Array[String]): Unit = {

    //建立配置文件对象
    val conf = new SparkConf().setMaster("local[*]").setAppName("MY")
    //创建sc对象
    val sc = new SparkContext(conf)
    val rdd = sc.makeRDD(List(("a",1),("b",5),("a",5),("b",2)))
    //partitionBy 指定分区
    val partitionBy: RDD[(String, Int)] = rdd.partitionBy(new MyOwnDefPartition(2))
    //reduceByKey 根据key聚合
    val reduceByKeyRdd: RDD[(String, Int)] = rdd.reduceByKey(_+_)
    //groupByKey 根据key分组
    val groupByKey: RDD[(String, Iterable[Int])] = rdd.groupByKey()
    val groupByKeySum: RDD[(String, Int)] = groupByKey.map {
      case (k, v) => (k, v.sum)
    }
    //aggregateByKey 入参:初始值 分区内函数 分区间函数
    val aggByKey: RDD[(String, Int)] = rdd.aggregateByKey(0)((_+_),(_+_))
    //foldByKey 入参 初始值 分区和分区间函数一致
    val foldByKeyRdd: RDD[(String, Int)] = rdd.foldByKey(0)(_+_)
    //combineByKey 入参 value的类型 分区内函数 分区间函数
    val combineByKeyRdd: RDD[(String, Int)] = rdd.combineByKey(
      data => data,
      (da: Int, v) => da + v,
      (da1: Int, da2: Int) => da1 + da2
    )
    //求平均数
    //groupByKey方式
    val avgGroupByKey: RDD[(String, Int)] = rdd.groupByKey().map {
      case (k, v) => (k, v.sum / v.size)
    }
    //reduceByKey方式
    val avgReduceByKey: RDD[(String, Int)] = rdd.map {
      case (word, num) => (word, (num, 1))
    }.reduceByKey {
      case (acc1, acc2) => (acc1._1 + acc2._1, acc1._2 + acc2._2)
    }.map {
      case (word, sum) => (word, sum._1 / sum._2)
    }
    //combineByKey方式
    val avgCombineByKey: RDD[(String, Int)] = rdd.combineByKey(
      (_, 1),
      (t1: (Int, Int), v) => (t1._1 + v, t1._2 + 1),
      (t2: (Int, Int), t3: (Int, Int)) => (t2._1 + t3._1, t2._2 + t2._2)
    ).map {
      case (word, sum) => (word, sum._1 / sum._2)
    }
    avgCombineByKey.collect().foreach(println)
    //关闭sc
    sc.stop()
  }


}

//自定义拦截器
class MyOwnDefPartition(partitions: Int) extends Partitioner{
  override def numPartitions: Int = partitions
  override def getPartition(key: Any): Int = {
    val tup: (String, Int) = key.asInstanceOf[(String,Int)]
    if (tup == "a"){
      1
    }else{
      0
    }
  }
}

    val rdd: RDD[(Int, String)] = sc.makeRDD(Array((3,"aa"),(6,"cc"),(2,"bb"),(1,"dd")))
    //sortByKey  排序
    val sortByKeyRdd: RDD[(Int, String)] = rdd.sortByKey()
    //mapValues 相同的key对value操作
    val mapValuesRdd: RDD[(Int, String)] = rdd.mapValues("||||" + _)
    val rdd1: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c")))
    val rdd2: RDD[(Int, Int)] = sc.makeRDD(Array((1, 4), (2, 5), (4, 6)))
    val joinRdd: RDD[(Int, (String, Int))] = rdd1.join(rdd2)
    val cogroupRdd: RDD[(Int, (Iterable[String], Iterable[Int]))] = rdd1.cogroup(rdd2)

计算各个TopN:

    //建立配置文件对象
    val conf = new SparkConf().setMaster("local[*]").setAppName("MY")
    //创建sc对象
    val sc = new SparkContext(conf)
    val logRdd: RDD[String] = sc.textFile("D:\\ideaWorkspace\\scala0105\\spark-0105\\input\\agent.log")
    val resRdd: RDD[(String, List[(String, Int)])] = logRdd.map {
      log => {
        val fileds: Array[String] = log.split(" ")
        (fileds(1) + "-" + fileds(fileds.length - 1), 1)
      }
    }.reduceByKey(_ + _).map {
      case (pro, adCount) => {
        (pro.split("-")(0), (pro.split("-")(1), adCount))
      }
    }.groupByKey().mapValues {
      values => {
        values.toList.sortBy(_._2).reverse.take(3)
      }
    }
    resRdd.collect().foreach(println)
    //关闭sc
    sc.stop()

二、Action(行动算子)

行动算子会触发整个任务的执行,因为转换算子是懒加载,并不会立即执行。

1)、reduce:对分区和分区间元素进行聚合,返回集合内数据类型

2)、collect:对数分区间数据进行聚合,返回数组,把executor的数据聚合在driver端

3)、foreach:对分区的数据进行遍历,针对于executor端

4)、count:计算RDD中元素个数

5)、first:取RDD中第一个元素

6)、take:取RDD中前几个元素

7)、takeOrdered:取排序后的RDD中前几个

8)、aggreate:对RDD中的元素进行聚合,参数:初始值、分区内函数、分区间函数,此算子初始值分别在分区内和分区间都参与运算

9)、fold:aggreate的简单版,代表分区内和分区间计算函数相同

10)、countByKey:统计KV类型RDD的key的数量

11)、save相关:saveAsTextFile、saveAsObjectFile、saveAsSequenceFile(正对KV类型RDD)

    val rdd: RDD[(Int, String)] = sc.makeRDD(List((1, "a"), (1, "a"), (1, "a"), (2, "b"), (3, "c"), (3, "c")))
    //reduce
    rdd.reduce{
      case (t1,t2) => (t1._1,t1._2)
    }
    //collect
    rdd.collect()
    //foreach
    rdd.foreach(println)
    //count
    rdd.count()
    //first
    rdd.first()
    //take
    rdd.take(2)
    //takeOrdered
    rdd.takeOrdered(2)
    //aggreate
    rdd.aggregate((0,0))(
      (t1:(Int,Int),v) =>(t1._1,t1._2),
      (t2:(Int,Int),t3:(Int,Int)) => (t2._1,t3._2)
    )
    //fold
    rdd.fold((0,"0"))(
      (t2:(Int,String),t3:(Int,String)) => (t2._1,t3._2)
    )
    //countByKey
    rdd.countByKey()
    //save
    rdd.saveAsTextFile("")
    rdd.saveAsSequenceFile("")
    rdd.saveAsObjectFile("")

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值