简述:

Spark的算子分为转换算子(Transformation)和行动算子(Action)。
转换算子将RDD转换成新的RDD,或者将文件系统的数据转换成一个RDD,行动算子会形成一个job。

转换算子(很重要!):

转换算子分为:Value类型,双Value类型和Key-Value类型。

Value类型
1、map
函数签名:def map[U: ClassTag](f:T => U): RDD[U]
功能说明:参数f是一个函数,它可以接收一个参数。当某个RDD执行map方法时,会遍历该RDD中的每一个数据项,并依次应用f函数,从而产生一个新的RDD。即这个新RDD中的每一个元素都是原来RDD中每一个元素依次应用f函数而得到的。
案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
    val value: RDD[Int] = rdd.map(_ * 2)
    value.collect().foreach(println)
  }

运行结果:

spark 列转json函数 spark转换函数_Boo


2、mapPartitions

函数签名:def mapPartitions[U: Class Tag](f: lterator[T] => lterator[U],preservesPartitioning: Boolean = false): RDD[U]

功能说明:mapPartitions是以分区为单位执行map

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
    rdd.mapPartitions(datas => datas.map(_ * 2)).collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_scala_02


3、mapPartitionsWithIndex

函数签名:def mapPartitionsWithIndex[U: ClassTag](f: (Int,lterator[T]) => lterator[U],preservesPartitioning: Boolean = false): RDD[U]

功能说明:类似于mapPartitions,比mapPartitions多一个参数来表示分区号

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
    rdd.mapPartitionsWithIndex((index, datas) => {
      datas.map((index, _))
    }).collect().foreach(println)
    rdd.mapPartitionsWithIndex((index, datas) => {
      index match {
        case 1 => datas.map(_ * 2)
        case _ => datas
      }
    }).collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_Boo_03


4、flatMap

函数签名:def flatMap[U: ClassTag](f:T => TraversableOnce[U]):RDD[U]

功能说明:与map操作类似,将RDD中的每一个元素通过应用f函数依次转换为新的元素,并封装到RDD中。

区别:在flatMap操作中,f函数的返回值是一个集合,并且会将每一个该集合中的元素拆分出来放到新的RDD中。

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd = sc.makeRDD(List(List(1, 2), List(3, 4), List(5, 6)), 2)
    rdd.flatMap(x => x).collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_spark_04


5、glom

函数签名:def glom(): RDD[Array[T]]

功能说明:该操作将RDD中每一个分区变成一个数组,并放置在新的RDD中,数组中元素的类型与原分区中元素类型一致。分区转换为数组

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6), 2)
    rdd.glom().collect().foreach(println)
    sc.stop()
  }

spark 列转json函数 spark转换函数_spark 列转json函数_05


6、groupBy

函数签名:def groupBy[K](f: T => K)(implicit kt: ClassTag[K]):RDD[(K, lterable[T])]

功能说明:进行分组,按照传入函数的返回值进行分组。将相同的key对应的值放入一个迭代器。

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd = sc.makeRDD(List("zz", "ss", "lili", "sisi", "zz", "ss"))
    rdd.groupBy(x => x).collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_Boo_06


7、filter

函数签名:def filter(f: T => Boolean): RDD[T]

功能说明:接收一个返回值为布尔类型的函数作为参数。当某个RDD调用filter方法时,会对该RDD中每一个元素应用f函数,如果返回值类型为true,则该元素会被添加到新的RDD中。

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6), 2)
    rdd.filter(_ % 2 == 0).collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_Boo_07


8、distinct

函数签名:def distinct(): RDD[T]

功能说明:对内部的元素去重,并将去重后的元素放到新的RDD中。

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkCoreTest")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    //创建rdd
    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 5, 4, 3, 2, 1), 5)
    rdd.mapPartitionsWithIndex((index, datas) => {
      println(index + "-->" + datas.mkString(","))
      datas
    }).collect()
    //对rdd中的数据进行去重
    val rdd1: RDD[Int] = rdd.distinct()
    rdd1.mapPartitionsWithIndex((index, datas) => {
      println(index + "-->" + datas.mkString(","))
      datas
    }).collect()
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_Boo_08


9、coalesce

函数签名:def coalesce( numPartitions: Int, shuffe :Boolean = false,partitionCoalescer: Option[PartitionCoalescer] = Option.empty)

(implicit ord:Ordering[T] = null) : RDD[T]

功能说明:缩减分区数,用于大数据集过滤后,提高小数据集的执行效率。

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6), 3)
    rdd.mapPartitionsWithIndex((index, datas) => {
      println(index + "-->" + datas.mkString(","))
      datas
    }).collect()
    println("---------")
    //缩减分区
        val rdd1: RDD[Int] = rdd.coalesce(2)
        rdd1.mapPartitionsWithIndex((index,datas)=>{
          println(index+"-->"+datas.mkString(","))
          datas
        }).collect()
    //如果使用coalesce扩大分区,不起作用,底层没有执行shuffle
    //如果扩大分区,使用repartition
//    val rdd2: RDD[Int] = rdd.repartition(4)
//    rdd2.mapPartitionsWithIndex((index, datas) => {
//      println(index + "-->" + datas.mkString(","))
//      datas
//    }).collect()
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_scala_09


10、sortBy

函数签名:def sortBy[K]( f:(T) =>K,ascending: Boolean = true,numPartitions: Int = this.partitions.length)(implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T]

功能说明:该操作用于排序数据。在排序之前,可以将数据通过f函数进行处理,之后按照f函数处理的结果进行排序,默认为正序排列。排序后新产生的RDD的分区数与原RDD的分区数一致。

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[Int] = sc.makeRDD(List(4, 2, 1, 7, 5, 6))
    //升序排序
    //val rdd1: RDD[Int] = rdd.sortBy(x => x)
    //降序排序
    val rdd1: RDD[Int] = rdd.sortBy(x => x, false)
    rdd1.collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_spark 列转json函数_10


双Value类型

双Value类型算子有union、subtract、 intersection、zip,都比较简单,所以一起介绍。

案例说明:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
        //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)

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

    //并集
//    rdd1.union(rdd2).collect().foreach(println)

    //交集
//    rdd1.intersection(rdd2).collect().foreach(println)

    //差集
//    rdd1.subtract(rdd2).collect().foreach(println)
//    println("-------")
//    rdd2.subtract(rdd1).collect().foreach(println)

    //拉链  分区数必须一样,不然会报错,分区中元素的个数必须保持一致
    rdd1.zip(rdd2).collect().foreach(println)
    sc.stop()
  }

Key-Value类型
1、partitionBy
函数签名:def partitionBy(partitioner: Partitioner): RDD[(K,V)]
功能说明:将RDD[K,V]中的K按照指定Partitioner重新进行分区;如果原有的partionRDD和现有的partionRDD是一致的话就不进行分区,否则会产生Shuffle过程。
案例实现:

object Spark01_partitionby {
  def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
        val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
        //创建SparkContext对象
        val sc: SparkContext = new SparkContext(conf)

    //rdd 本身没有partitionBy功能,隐式转换动态给kv类型扩展了这个功能
    val rdd: RDD[(Int, String)] = sc.makeRDD(List((1, "aaa"), (2, "bbb"), (3, "ccc")), 3)
    rdd.mapPartitionsWithIndex((index,datas)=>{
      println(index+"-->"+datas.mkString(","))
      datas
    }).collect
    sc.stop()
  }
}

运行结果:

spark 列转json函数 spark转换函数_spark_11

2、reduceByKey
函数签名: def reduceByKey(func: (V,V) =>V):RDDI(K, V)]def reduceByKey(func: (v, V) => V, numPartitions : Int):RDD[(K,V)]
功能说明:该操作可以将RDD[K,v]中的元素按照相同的K对v进行聚合。其存在多种重载形式,还可以设置新RDD的分区数。
案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
        //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[(String, Int)] = sc.makeRDD(List(("a", 1), ("b", 3), ("a", 5), ("b", 2)))
    rdd.reduceByKey(_+_).collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_List_12


3、groupByKey()

函数签名:def groupByKey():RDD[(K, Iterable[V])]

功能说明:groupByKey对每个key进行操作,但只生成一个seq,并不进行聚合。该操作可以指定分区器或者分区数(默认使用HashPartitioner)

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
        //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[(String, Int)] = sc.makeRDD(List(("a", 1), ("b", 5), ("a", 5), ("b", 2)))
//    rdd.groupBy(x=>x._1).collect().foreach(println)

    val rdd1: RDD[(String, Iterable[Int])] = rdd.groupByKey()
    //rdd1.collect().foreach(println)
    val rdd2: RDD[(String, Int)] = rdd1.map {
      case (key, datas) => {
        (key, datas.sum)
      }
    }
    rdd2.collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_spark 列转json函数_13


4、aggregateByKey

函数签名:def aggregateByKey[U: ClassTag](zeroValue: U)(seqOp: (u,V) =>U, combOp:(U,U)=>U):RDD[(K, U)]

功能说明:处理分区内和分区间逻辑

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
        //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[(String, Int)] = sc.makeRDD(List(("a", 3), ("a", 2), ("c", 4), ("b", 3), ("c", 6), ("c", 8)), 2)
    rdd.mapPartitionsWithIndex((index,datas)=>{
      println(index+"-->"+datas.mkString(","))
      datas
    }).collect()
    val rdd1: RDD[(String, Int)] = rdd.aggregateByKey(0)((x, y) => {
      if (x > y)
        x
      else
        y
    }, _ + _)
    rdd1.mapPartitionsWithIndex((index,datas)=>{
      println(index+"-->"+datas.mkString(","))
      datas
    }).collect()
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_List_14


5、foldByKey

函数签名:def foldByKey(zero Value: V)(func: (V, V)=> V): RDD[(K,V)]

功能说明:aggregateByKey的简化操作,分区内和分区间的计算规则一样

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
        //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[(String, Int)] = sc.makeRDD(List(("a", 3), ("a", 2), ("c", 4), ("b", 3), ("c", 6), ("c", 8)), 2)
    rdd.foldByKey(0)(_+_).collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_Boo_15


6、combineByKey

函数签名:def combineByKey[C](createCombiner: V=> C,mergevalue: (C, V) => C,mergeCombiners: (c, c)=> C): RDD[(K,C)]

功能说明:针对相同K,将V合并成一个集合。

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
        //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)

    val rdd: RDD[(String, Int)] = sc.makeRDD(List(("zs", 90), ("lisi", 80), ("zs", 80), ("lisi", 70)))

    //方法一  groupByKey
    //如果分组之后,某个组的数据很大  会造成单点压力
//    val rdd1: RDD[(String, Iterable[Int])] = rdd.groupByKey()
//    val rdd2: RDD[(String, Int)] = rdd1.map {
//      case (name, score) => {
//        (name, score.sum / score.size)
//      }
//    }
//    rdd2.collect().foreach(println)

    //方法二  reduceByKey  (name, score)=>(name,(score,1))
//    val rdd1: RDD[(String, (Int, Int))] = rdd.map {
//      case (name, score) => {
//        (name, (score, 1))
//      }
//    }
//    val rdd2: RDD[(String, (Int, Int))] = rdd1.reduceByKey {
//      (t1, t2) => {
//        (t1._1 + t2._1, t1._2 + t2._2)
//      }
//    }
//    rdd2.map{
//      case(name,(score,num))=>{
//        (name,score/num)
//      }
//    }.collect().foreach(println)

    //方法三
    val rdd1: RDD[(String, (Int, Int))] = rdd.combineByKey(
      (_, 1),
      (tup1: (Int, Int), v) => {
        (tup1._1 + v, tup1._2 + 1)
      },
      (tup2: (Int, Int), tup3: (Int, Int)) => {
        (tup2._1 + tup3._1, tup2._2 + tup3._2)
      }
    )
    val rdd2: RDD[(String, Int)] = rdd1.map {
      case (name, (score, num)) => {
        (name, score / num)
      }
    }
    rdd2.collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_spark 列转json函数_16


7、sortByKey

函数签名:def sortByKey(ascending: Boolean = true,numPartitions: lnt = self.partitions.length) :RDD[(K,V)]

功能说明:在一个(K,V)的RDD上调用,K必须实现ordered接口,返回一个按照key进行排序的(K,V)的RDD

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
    //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[(Int, String)] = sc.makeRDD(Array((3, "aa"), (6, "cc"), (2, "bb"), (1, "dd")))

    //按照key对rdd中的元素进行排序,默认升序
    rdd.sortByKey().collect().foreach(println)
    //降序
    rdd.sortByKey(false).collect().foreach(println)
  }

运行结果:

spark 列转json函数 spark转换函数_scala_17


8、mapValues

函数签名:def mapValues[U](f: V => U): RDD[(K,U)]

功能说明:针对于(K,v)形式的类型只对v进行操作

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
        //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)
    val rdd: RDD[(Int, String)] = sc.makeRDD(List((1, "a"), (1, "d"), (2, "b"), (3, "c")))
    rdd.mapValues("|||"+_).collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_spark_18


9、join

函数签名:def join[W](other: RDD[(K, W)]):RDD[(K, (V, W))]

def join[W](other: RDD[(K,W)], numPartitions: Int): RDD[(K, (V, W))]

功能说明:在类型为(K,v)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(v,W))的RDD

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
        //创建SparkContext对象
    val sc: SparkContext = new SparkContext(conf)

    val rdd: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c")))
    val rdd1: RDD[(Int, Int)] = sc.makeRDD(Array((1, 4), (2, 5), (4, 6)))
    //相当于内连接,将两个rdd中的key相同的数据匹配,如果key匹配不上,那么数据不关联
//    rdd.join(rdd1).collect().foreach(println)

//    rdd.leftOuterJoin(rdd1).collect().foreach(println)
val rdd2: RDD[(Int, (Iterable[String], Iterable[Int]))] = rdd.cogroup(rdd1)
    rdd2.collect().foreach(println)
    sc.stop()
  }

运行结果:

spark 列转json函数 spark转换函数_scala_19

行动算子:

行动算子有reduce、collect、foreach、first、take、takeOrdered、aggregate、fold、countByKey、save等,都比较简单。
1、reduce
函数签名:def reduce(f: (T, T) => T): T
功能说明:f函数聚集RDD中的所有元素,先聚合分区内数据,再聚合分区间数据

2、collect
函数签名:def collect(): Array[T]
功能说明:以数组的形式返回数据集

3、foreach
函数签名:def foreach(f:T => Unit): Unit
功能说明:遍历RDD中每一个元素

4、first
函数签名:def first(): T
功能说明:返回RDD中的第一个元素

5、take
函数签名:def take(num: Int): Array[T]
功能说明:返回由RDD前n个元素组成的数组

6、takeOrdered
函数签名:def takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T]
功能说明:返回该RDD排序后的前n个元素组成的数组

7、aggregate
函数签名:def aggregateU: ClassTag(seqOp: (U,T)=>U, combOp:(U,U) => U):U
功能说明: aggregate函数将每个分区里面的元素通过分区内逻辑和初始值进行聚合,然后用分区间逻辑和初始值(zeroValue)进行操作。注意:分区间逻辑再次使用初始值和aggregateByKey是有区别的。

8、fold
函数签名:def fold{zerovalue:T)(op:(T,T) => T): T
功能说明:折叠操作,aggregate的简化操作,分区内逻辑和分区间逻辑相同

9、countByKey
函数签名:def countByKey(): Map[K, Long]
功能说明:统计每种key的个数

10、save
(1)saveAsTextFile(path)保存成Text文件
(2)saveAsSequenceFile(path) 保存成Sequencefile文件
(3)saveAsObjectFile(path) 序列化成对象保存到文件

案例实现:

def main(args: Array[String]): Unit = {
    //创建Spark配置对象文件
      val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("Spark01")
        //创建SparkContext对象
      val sc: SparkContext = new SparkContext(conf)

//    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4))

    //reduce
//    println(rdd.reduce(_ + _))

    //collect
//    rdd.collect().foreach(println)

    //count
//    println(rdd.count())

    //first
//    println(rdd.first())

    //take 返回rdd中前n个元素组成的数组
//    println(rdd.take(2).mkString(","))

    //takeOrdered 获取rdd排序后 前n的元素组成的数组
//    println(rdd.takeOrdered(3).mkString(","))

    //aggregate
//    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 8)
//
//    println(rdd.aggregate(10)(_ + _, _ + _))

    //fold 是aggregate的简化版
//    rdd.fold(10)(_+_)
    //countByKey 统计每种key出现的次数
//    val rdd: RDD[(Int, String)] = sc.makeRDD(List((1, "a"), (1, "a"), (1, "a"), (2, "b"), (3, "c"), (3, "c")))
//    println(rdd.countByKey())

    val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)

    rdd.saveAsTextFile("D:\\IDEAprojects\\spark_demo\\output")
    rdd.saveAsObjectFile("D:\\IDEAprojects\\spark_demo\\output1")
    rdd.map((_,1)).saveAsSequenceFile("D:\\IDEAprojects\\spark_demo\\output2")
  }