1.Spark的一些基本名词解释

ClusterManager:在Standalone模式中即为Master(主节点),控制整个集群,监控Worker。在YARN模式中为资源管理器。
Worker:从节点,负责控制计算节点,启动Executor。在YARN模式中为NodeManager,负责计算节点的控制。
Driver:运行Application的main()函数并创建SparkContext。
Executor:执行器,在worker node上执行任务的组件、用于启动线程池运行任务。每个Application拥有独立的一组Executors。
SparkContext:整个应用的上下文,控制应用的生命周期。
RDD:Spark的基本计算单元,一组RDD可形成执行的有向无环图RDD Graph。
DAG Scheduler:实现将Spark作业分解成一到多个Stage,每个Stage根据RDD的Partition个数决定Task的个数,然后生成相应的Task set放到TaskScheduler中。
TaskScheduler:将任务(Task)分发给Executor执行。
Stage:一个Spark作业一般包含一到多个Stage。
Task:一个Stage包含一到多个Task,通过多个Task实现并行运行的功能。
Transformations:转换(Transformations) (如:map, filter, groupBy, join等),Transformations操作是Lazy的,也就是说从一个RDD转换生成另一个RDD的操作不是马上执行,Spark在遇到Transformations操作时只会记录需要这样的操作,并不会去执行,需要等到有Actions操作的时候才会真正启动计算过程进行计算。
Actions:操作(Actions) (如:count, collect, save等),Actions操作会返回结果或把RDD数据写到存储系统中。Actions是触发Spark启动计算的动因。
SparkEnv:线程级别的上下文,存储运行时的重要组件的引用。
SparkEnv内创建并包含如下一些重要组件的引用。
MapOutPutTracker:负责Shuffle元信息的存储。
BroadcastManager:负责广播变量的控制与元信息的存储。
BlockManager:负责存储管理、创建和查找块。
MetricsSystem:监控运行时性能指标信息。
SparkConf:负责存储配置信息。


2. Spark的基本编程

1. SparkContext

spark count distinct优化 spark counter_spark

2. RDD

RDD是弹性分布式数据集,是spark的基本计算单位。SparkRDD支持两种类型的操作,Transformation,Action。如果更加细微的划分,还有输入算子(textFile,parallelize),转换算子(map…),缓存算子(cache、persist),输出算子(foreach、count、save等)。

def SparkOps: Unit = {

       val conf = new SparkConf()

               .setAppName("SparkTransformation")

               .setMaster("local[*]")
       val sc = new SparkContext(conf)
    //调用算子方法
      sc.stop()
   }

3. Transformation( 转换算子)

3.1.1 map(一对一)

def mapOps(sc: SparkContext): Unit = {
        val list = 1 to 7
        val listRDD = sc.parallelize(list)
        val retRDD = listRDD.map(_ * 7)
        retRDD.foreach(println)
    }

3.1.2 flatmap(一对多)

def flatmapOps(sc:SparkContext):Unit={
        val list = List(
            "yan xin xin",
            "zhai zhao pin"
        )
        val listRDD = sc.parallelize(list)
  
       val wordsRDD = listRDD.flatMap(line => line.split("\\s+"))
      wordsRDD.foreach(println)
}

3.1.3 filter(过滤)

/*
        stu
            id  name    age     gender
     */

    def filterOps(sc: SparkContext): Unit = {
        val stuList = List(
            "1 AA  18  0",
            "2 bb  28  1",
            "3 CC  16  0",
            "4 DD  23  1"
        )
        val stuRDD:RDD[String] = sc.parallelize(stuList)
        val girls = stuRDD.filter(stu => {
//            val fields = stu.split("\\s+")
//            val gender = fields(3)
//            gender == "0"
            stu.endsWith("0")
        })
        girls.foreach(println)
    }

3.1.4 sample(抽样算子)

def sampleOps(sc:SparkContext): Unit = {

        val list = 1 to 10000

        val listRDD = sc.parallelize(list)

        val sampledRDD = listRDD.sample(false, 0.2)

        println("抽取样本空间的大小:" + sampledRDD.count())

    }

3.1.5 union

在spark中的union操作,作用和DB中的union all的作用相同,不会去重。

//作用类似于union all

    def unionOps(sc: SparkContext): Unit = {

        val listRDD1 = sc.parallelize(1 to 5)
        val listRDD2 = sc.parallelize(3 to 10)
        val unionRDD = listRDD1.union(listRDD2)
        unionRDD.foreach(println)

    }

3.1.6 join

表关联操作,这里的表是泛化的概念,只要是数据集都可以理解为表
join有哪些操作:
交叉连接:across join 写sql的时候有表的关联,但是没有on的连接字段,这会造成笛卡尔积。

3.1.7 groupbykey

对RDD中的数据按照key进行分组,首先必须要有key,数据类型必须是(key,value)经过分组之后相同的数据拉到一起,组成一个集合
(k,v).groupByKye()–>(k,Iterable[v])

def gbkOps(sc: SparkContext): Unit = {

        val stu = List(

            "1 鹿晗  22  bd01",

            "2 杨幂  25  bd02",

            "3 范冰冰  24  bd01",

            "4 梁朝伟 18  bd03",

            "5 黄渤 18  bd01",

            "4 张震 18  bd02"

        )



        //按照班级进行分组 -->sql中的groupBy

        val stuRDD:RDD[String] = sc.parallelize(stu)

        val class2Info:RDD[(String, String)] = stuRDD.map(stuLine => {

            val clazz = stuLine.substring(stuLine.indexOf("bd"))

            val info = stuLine.substring(0, stuLine.indexOf("bd")).trim

            (clazz, info)

        })



        val gbkRDD:RDD[(String, Iterable[String])] = class2Info.groupByKey()





        gbkRDD.foreach{case (clazz, infos) => {

            /*for(info <- infos) {

                println(s"${clazz} ---> ${info}")

            }*/

            println(s"${clazz} ---> ${infos}")

        }}

        println("-----------------------------------------")

        //ClassTag是类型的标记接口

        val gbRDD:RDD[(String, Iterable[String])] = stuRDD.groupBy(stuLine => stuLine.substring(stuLine.indexOf("bd")))(

            ClassTag.Object.asInstanceOf[ClassTag[String]]

        )

        gbRDD.foreach{case (clazz, infos) => {

            println(s"${clazz} ===> ${infos}")

        }}

    }

3.1.8 reducebykey

按key进行reduce操作

def rbkOps(sc: SparkContext): Unit = {

        val list = List(

            "yan xin     xin",

            "zhai zhao pin"

        )



        val listRDD = sc.parallelize(list)



        val wordsRDD = listRDD.flatMap(line => line.split("\\s+"))

        val pairsRDD:RDD[(String, Int)]= wordsRDD.map((_, 1))

        val rbkRDD:RDD[(String, Int)] = pairsRDD.reduceByKey(_+_)

        rbkRDD.foreach(println)

    }

3.1.9 combinebykey

combinebykey模拟Reducebykey

object _02CombineByKey2ReduceByKeyOps {

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

         val conf = new SparkConf()

                     .setAppName("cbk2rbk")

                     .setMaster("local[*]")

         val sc = new SparkContext(conf)

 

 

 

         val list = List(

             "hello you hello me",

             "hello you shit me",

             "hello you oh shit",

             "me you hello me"

         )

 

         val listRDD = sc.parallelize(list)

 

         val pairsRDD:RDD[(String, Int)] = listRDD.flatMap(_.split("\\s+")).map((_, 1))

 

         //reduceByKey

         println("-----------传统的rbk操作--------------")

         pairsRDD.reduceByKey(_+_).foreach(println)

         println("-----------combineByKey模拟rbk操作--------------")

         pairsRDD.combineByKey(createCombiner, mergeValue, mergeCombiners)

                     .foreach(println)

 

 

         sc.stop()

     }

 

     /**求:1 + 10

       * var sum1 = 1

       *

       * for(i <- 2 to 10) {

       *     sum1 = sum1 + i

       * }

       * var sum2 = 0

       * for(i <- 1 to 10) {

       *     sum2 = sum2 + i

       * }

       *  初始化聚合的结果类型

       */

     def createCombiner(value:Int):Int = {

         value

     }

     //分区内的聚合操作(map端的操作)

     def mergeValue(sum:Int, value:Int):Int = {

         sum + value

     }

     //分区间的聚合操作(reduce端的操作)

     def mergeCombiners(sum1:Int, sum2:Int): Int = {

         sum1 + sum2

     }

 }

 ```
 combinebykey模拟groupbykey
2. combineByKey模拟groupByKey



 ```scala

 object _03CombineByKey2GroupByKeyOps {

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

         val conf = new SparkConf()

                     .setAppName("cbk2gbk")

                     .setMaster("local[2]")//thread -- task--->partition(block)

         val sc = new SparkContext(conf)
         val stu=list(
         "1 鹿晗 22 bd01",
         "2 杨幂  25  bd02",
         "3 范冰冰  24  bd01",
         "4 梁朝伟 18  bd03",
         "5 黄渤 18  bd01",
         "4 张震 18  bd02"
        
         )
 

//按照班级进行分组 -->sql中的groupBy

         val stuRDD:RDD[String] = sc.parallelize(stu)

         val class2Info:RDD[(String, String)] = stuRDD.map(stuLine => {

             val clazz = stuLine.substring(stuLine.indexOf("bd"))

             (clazz, stuLine)

         })

         class2Info.saveAsTextFile("file:///E:/data/out/cbk")

         val gbkRDD:RDD[(String, Iterable[String])] = class2Info.groupByKey()

 

         println("-----------传统的gbk操作--------------")

         gbkRDD.foreach{case (clazz, infos) => {

             println(s"${clazz} ---> ${infos}")

         }}

         println("-----------combineByKey模拟gbk操作--------------")

 

         class2Info.combineByKey(

                 (info:String) => createCombiner(info),

                 (buffer:ArrayBuffer[String], info:String) => mergeValue(buffer, info),

                 (buffer1:ArrayBuffer[String], buffer2:ArrayBuffer[String]) => mergeCombiners(buffer1, buffer2),

                 new MyPartitioner(3))//该分区动作不是combineByKey数据输入进来是对数据做分区,经过combineByKey计算完毕之后将结果做分区

            .saveAsTextFile("file:///E:/data/out/cbk1")   

         sc.stop()

     }

     /*

         初始化操作,确定聚合操作之后的结果类型

         在每一个分区内相同的key,需要调用一次该操作,并将其中的一个元素用于初始化操作

      */

     def createCombiner(info:String):ArrayBuffer[String] = {

         println("----createCombiner------>info: " + info)

         val ab = ArrayBuffer[String]()

         ab.append(info)

         ab

     }

     /**

       * 分区内的相同key的聚合操作

       *

       */

     def mergeValue(ab:ArrayBuffer[String], info:String):ArrayBuffer[String] = {

         println(s"----mergeValue------>ab:${ab.mkString(",")}《===》info: ${info}")

         ab.append(info)

         ab

     }

     /**

       * 分区间的相同key的聚合操作

       */

     def mergeCombiners(ab1:ArrayBuffer[String], ab2:ArrayBuffer[String]):ArrayBuffer[String] = {

         println(s"----mergeCombiners------>ab1:${ab1.mkString(",")}《===》ab2:${ab2.mkString(",")}")

         ab1 ++ ab2

     }

 }

 class MyPartitioner(partitions:Int) extends Partitioner {

     override def numPartitions = partitions

     override def getPartition(key: Any) = {

         val ret = key match {

             case clazz:String => {

                 //bd-1901-wh

                 val city = clazz.substring(clazz.lastIndexOf("-") + 1)

                 city match {

              ·       case "wh" => 0

                     case "bj" => 1

                     case "sz" => 2

                 }

             }

             case _ => 0

         }

         ret

     }

 }