spark初识与内核

一、什么是spark?

Spark,是一个大数据计算引擎,是一个用scala语言编写的计算框架,基于内存的快速、通用、可扩展的大数据分析引擎,能够计算大量的数据,例如hadoop中hdfs上的数据

二、为什么要学spark

mapreduce速度慢,数据量稍微大一点就要执行几分钟甚至更久,spark的计算引擎是基于内存,CPU核数进行计算的,速度比mapreduce快了大概10倍。

mapreduce逻辑只有map和reduce,map分开计算,reduce聚合处理,功能比较局限。spark1、除了map和reduce逻辑,还可以开窗、分组、缓存......,2、代码量减少很多。

三、sparkRDD理解

/**
* RDD: 弹性分布式数据集
* 弹性:数据量可大可小
* RDD类似于容器,但是本身存储的不是数据,是计算逻辑
* 当遇到行动算子的时候,整个spark作业才会被触发执行,是从第一个RDD开始执行,数据才开始产生流动
* 数据在RDD之间只是流动关系,不会存储
* 流动的数据量可以很大,也可以很小,所以称为弹性
* 分布式:
* spark本质上它是需要从HDFS中读取数据的,HDFS是分布式,数据block块将来可能会在不同的datanode上
* RDD中流动的数据,可能会来自不同的datanode中的block块数据
* 数据集:
* 计算流动过程中,可以短暂地将RDD看成一个容器,容器中有数据,默认情况下在内存中不会进行存储
* 后面会有办法将一个RDD的数据存储到磁盘中
*/

四、sparkRDD五大特性

  /**
* RDD的5大特性:
* 1、RDD是由一系列分区构成
* 注意:
* 1)读文件时的minPartitions参数只能决定最小分区数,实际读取文件后的RDD分区数,由数据内容本身以及集群的分布来共同决定的
* 2)若设置minPartitions的大小比block块数量还少的话,实际上以block块数量来决定分区数
* 3)产生shuffle的算子调用时,可以传入numPartitions,实际真正改变RDD的分区数,设置多少,最终RDD就有多少分区
*
* 2、算子是作用在每一个分区上的
* 3、RDD与RDD之间存在一些依赖关系
* 1)窄依赖 前一个RDD中的某一个分区数据只会到后一个RDD中的某一个分区  一对一的关系
* 2)宽依赖 前一个RDD中的某一个分区数据会进入到后一个RDD中的不同分区中  一对多的关系  也可以通过查看是否产生shuffle来判断
 * 3)整个spark作业会被宽依赖的个数划分若干个stage, Num(stage) = Num(宽依赖) + 1
* 4)当遇到产生shuffle的算子的时候,涉及到从前一个RDD写数据到磁盘中,从磁盘中读取数据到后一个RDD的现象,
*    注意:第一次触发执行的时候,磁盘是没有数据的,所以会从第一个RDD产生开始执行
*    当重复触发相同的执行的时候,对于同一个DAG有向无环图而言,会直接从shuffle之后的RDD开始执行,可以直接从磁盘读取数据。
* 5)一个阶段中,RDD有几个分区,就会有几个并行task任务
*
* 4、kv算子只能作用在kv的RDD上
* 5、spark会提供最优的任务计算方式,只移动计算,不移动数据。
*/

//spark统计每个单词个数
object wordCount {
  def main(args: Array[String]): Unit = {
    //创建spark配置文件对象
    val conf: SparkConf = new SparkConf()
    //设置运行模式
    //如果是本地local模式运行的话,需要设置setMaster
    //将来如果是集群进行,将这句话注释即可
    conf.setMaster("local")
    //设置spark作业的名字
    conf.setAppName("wordCount")
    //创建spark core上下文环境对象
    val sc: SparkContext = new SparkContext(conf)

    //读取文件,每次读取一行
    //RDD是spark core中的核心数据结构,将来运行的时候,数据会在RDD之间流动,默认基于内存计算
    val lineRDD: RDD[String] = sc.textFile("spark/data/word.txt")

    //将lineRDD数据用符号进行分割
    val wordRDD: RDD[String] = lineRDD.flatMap((line: String) => line.split(","))

    //将每一个单词组成一个(word,1)
    val kvRDD: RDD[(String, Int)] = wordRDD.map((_, 1))
    //根据键进行分组
    val resRDD: RDD[(String, Iterable[(String, Int)])] = kvRDD.groupBy(_._1, numPartitions = 4)

    val resRDD2: RDD[(String, Int)] = resRDD.map((e: (String, Iterable[(String, Int)])) => (e._1, e._2.size))
    resRDD2.map((kv:(String,Int))=>{
      println("============================")
      (kv._1,kv._2)
    })
    //打印
    resRDD2.foreach(println)

五、转换算子

5.1、转换算子:Map

object Demo1Map {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
    conf.setMaster("local")
    conf.setAppName("map算子演示")
    val sc: SparkContext = new SparkContext(conf)

    //读取文件,每次读取一行
    val lineRDD: RDD[String] = sc.textFile("spark/data/students.txt")
    //map操作算子:将rdd中的数据依次取出,传递给后面函数逻辑,将计算后的数据返回到新的rdd中
    //将rdd中的数据依次取出,处理完的数据返回下一个rdd直接继续执行后续的逻辑
    val rdd1: RDD[(String, String, String, String, String)] = lineRDD.map((line: String) => {
      println("==============你过来呀===========")
      val array: Array[String] = line.split(",")
      (array(0), array(1), array(2), array(3), array(4))
    })

    //foreach是一个行动算子
    rdd1.foreach(println)

  }
}

5.2、转换算子:Filter

object Demo2Filter {
  def main(args: Array[String]): Unit = {
    //创建spark配置文件对象
    val conf: SparkConf = new SparkConf()
    //设置运行模式
    conf.setMaster("local")
    //设置spark作业名字
    conf.setAppName("filter算子演示")
    //创建spark core上下文环境连接对象
    val sc: SparkContext = new SparkContext(conf)

    //需求:过滤出所有的男生
    //filter转换算子:将rdd中的数据依次取出,传递给后面的函数,跟map一样,也是依次传递一条
    val lineRDD: RDD[String] = sc.textFile("scala/data/students.txt")

    val resRDD: RDD[String] = lineRDD.filter((line: String) => {
      var b: Boolean = false
      if ("女".equals(line.split(",")(3))) {
        println("=========这是女生=========")
      } else {
        println("==========这是男生=========")
        b = "男".equals(line.split(",")(3))
      }
      b
    })

  }
}

5.3、转换算子:flatMap

object Demo3FlatMap {
  def main(args: Array[String]): Unit = {
    //创建spark配置文件对象
    val conf: SparkConf = new SparkConf()
    //设置运行模式
    conf.setMaster("local")
    //设置spark作业的名字
    conf.setAppName("flatMap算子")
    //创建spark core 上下文环境对象
    val sc: SparkContext = new SparkContext(conf)

    //读取文件,每次读取一行
    val lineRDD: RDD[String] = sc.textFile("spark/data/wcs/words.txt")

    /**
     * flatMap: 将rdd数据中的每一条数据传给后面的函数,最终返回数组。或者序列进行扁平化,返回给新的集合
     */
    val rdd1: RDD[String] = lineRDD.flatMap((line: String) => {
      println("==========数据将被切分============")
      line.split("\\|")
    })
     rdd1.foreach(println)
  }
}

5.4、转换算子:sample

object Demo4Sample {
  def main(args: Array[String]): Unit = {
    //创建spark配置文件对象
    val conf: SparkConf = new SparkConf()
    //设置运行模式
    conf.setMaster("local")
    //设置spark作业的名字
    conf.setAppName("flatMap算子")
    //创建spark core 上下文环境对象
    val sc: SparkContext = new SparkContext(conf)

    val lineRDD: RDD[String] = sc.textFile("scala/data/students.txt")
    
    /**
     * sample抽样,1000条数据,抽0.1比例,结果的数量在100左右
     */
    val sampleRDD: RDD[String] = lineRDD.sample(withReplacement = false, fraction = 0.1)
    sampleRDD.foreach(println)
  }
}

5.5、转换算子:groupby

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

    val conf: SparkConf = new SparkConf()
    conf.setMaster("local")
    conf.setAppName("groupBy")
    val sc: SparkContext = new SparkContext(conf)

    //求每个班级的平均年龄
    val lineRDD: RDD[String] = sc.textFile("spark/data/students.txt")

    val arrRDD: RDD[Array[String]] = lineRDD.map((line: String) => line.split(","))

    //像这种RDD中的元素是(key,value)类型的,将RDD称为键值对RDD(kv格式RDD)
    val clazzWithAgeRDD: RDD[(String, Int)] = arrRDD.map {
      case Array(_, _, age: String, _, clazz: String) =>
        (clazz, age.toInt)
    }

    /**
     * groupBy 算子使用
     *
     * 1.group by 的算子,后面分组的条件是我们自己指定的
     * 2.spark中groupBy之后的所有的值都会被封装到一个Iterable迭代器中储存
     */
    val groupRDD: RDD[(String, Iterable[(String, Int)])] = clazzWithAgeRDD.groupBy((_._1))

    val resRDD: RDD[(String, Double)] = groupRDD.map((kv: (String, Iterable[(String, Int)])) => {
      val clazz: String = kv._1
      val avgAge: Double = kv._2.map(_._2).sum.toDouble / kv._2.size
      (clazz, avgAge)
    })

    resRDD.foreach(println)
  }

5.6、转换算子:groupbykey

object Demo6GroupByKey {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
    conf.setMaster("local")
    conf.setAppName("groupByKey")
    val sc: SparkContext = new SparkContext(conf)

    val lineRDD: RDD[String] = sc.textFile("spark/data/students.txt")
    //求每个班级的平均年龄
    val arrayRDD: RDD[Array[String]] = lineRDD.map((line: String) => line.split(","))

    //像这种RDD中的元素是(key,value)类型的,将这种RDD称之为键值对RDD(kv格式RDD)
    val clazzWithAgeRDD: RDD[(String, Int)] = arrayRDD.map {
      case Array(_, _, age: String, _, clazz: String) =>
        (clazz, age.toInt)
    }

    /**
     * GroupByKey属于kv格式的算子,只能作用在kv格式的RDD上
     * 只有kv格式的RDD才能调用kv格式的算子
     */
    val groupByKey: RDD[(String, Iterable[Int])] = clazzWithAgeRDD.groupByKey()
    val resRDD: RDD[(String, Double)] = groupByKey.map((kv: (String, Iterable[Int])) => (kv._1, kv._2.sum.toDouble / kv._2.size))

    /**
     * spark core中 groupBy算子与groupByKey算子的区别
     * 1、代码格式上:
     * groupBy的分组条件可以自己指定,绝大部分的RDD都可以调用该算子,返回的是键和元素本身组成的迭代器构成的kv格式RDD
     * groupByKey算子,只能由kv格式的RDD进行调用,分组的条件会自动根据键进行分组,不需要在自己指定,返回的是键和值组成的迭代器构成的kv格式RDD
     *
     * 2、执行shuffle数据量来看
     * groupBy产生的shuffle数据量在一定程度上要大于groupByKey产生的shuffle数据量
     * groupByKey算子的执行效率要比groupBy算子的执行效率要高
     */

    resRDD.foreach(println)
   }
}

5.7、转换算子:reducebykey

object Demo7ReduceByKey {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
      .setMaster("local")
      .setAppName("reduceByKey")
    val sc: SparkContext = new SparkContext(conf)

    val lineRDD: RDD[String] = sc.textFile("spark/data/score.txt")
    val arrRDD: RDD[Array[String]] = lineRDD.map((line: String) => line.split(","))
    //分别使用groupByKey和reduceByKey计算每个学生的总分
    val idWithScoreRDD: RDD[(String, Int)] = arrRDD.map {
      case Array(id: String, _, score: String) =>
        (id, score.toInt)
    }

    val resRDD2: RDD[(String, Int)] = idWithScoreRDD.reduceByKey((v1: Int, v2: Int) => v1 + v2)
    resRDD2.foreach(println)
  }
}

    /**
     * groupByKey与reduceByKey的区别
     * 相同点:
     * 它们都是kv格式的算子,只有kv格式的RDD才能调用
     * 不同点:
     * 1)groupByKey只是单纯地根据键进行分组,分组后的逻辑可以在后续的处理中调用其他的算子实现
     * 2)reduceByKey 相当于MR中的预聚合,所以shuffle产生的数据量要比groupByKey中shuffle产生的数据量少,效率高,速度要快一些
     * 3)groupByKey的灵活度要比reduceByKey灵活度要高,reduceByKey无法做一些复杂的操作,比如方差。但是groupByKey可以在分组之后的RDD进行方差操作
     */

5.8、转换算子:Union

object Demo8Union {
  def main(args: Array[String]): Unit = {
      val conf: SparkConf = new SparkConf()
        .setMaster("local")
        .setAppName("转换算子Union")
      val sc: SparkContext = new SparkContext(conf)

    //parallelize:将scala的集合变成spark中的RDD
    val hlrRDD: RDD[(String, String)] = sc.parallelize(List(
      ("1001", "火灵儿"),
      ("1002", "火灵儿"),
      ("1003", "火灵儿"),
      ("1004", "火灵儿"),
      ("1005", "火灵儿")
    ))
    println(s"hlrRDD的分区数为${hlrRDD.getNumPartitions}")

    val jzyRDD: RDD[(String, String)] = sc.parallelize(List(
      ("1006", "姬紫月"),
      ("1007", "姬紫月"),
      ("1003", "火灵儿"),
      ("1008", "姬紫月"),
      ("1009", "姬紫月")
    ))
    println(s"jzyRDD的分区数为${jzyRDD.getNumPartitions}")

    val rdd1: RDD[(String, Int)] = sc.parallelize(List(
      ("1006", 11),
      ("1007", 22),
      ("1003", 33),
      ("1008", 44),
      ("1009", 55)
    ))
//    println(s"rdd1的分区数为${rdd1.getNumPartitions}")

    //两个RDD要想进行union合并,必须保证元素的格式和数据类型是一致的
    //分区数也会进行合并,最终的分区数由两个RDD总共的分区数决定
    // hlrRDD.union(rdd1)//报错,数据类型不一致

    val resRDD: RDD[(String, String)] = hlrRDD.union(jzyRDD)
    resRDD.foreach(println)
    println(s"resRDD的分区数为:${resRDD.getNumPartitions}")
  }
}

5.9、转换算子:join

  /**
   * join算子也是作用与kv格式的RDD
   */
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
      .setMaster("local")
      .setAppName("转换算子join")

    val sc: SparkContext = new SparkContext(conf)

    //parallelize:将scala中的集合变成spark中的RDD
    val rdd1: RDD[(String, String)] = sc.parallelize(List(
      ("1001", "黄忠"),
      ("1002", "赵云"),
      ("1003", "关羽"),
      ("1004", "张飞"),
      ("1005", "马虎")
    ))

    val rdd2: RDD[(String, String)] = sc.parallelize(List(
      ("1001", "看美女"),
      ("1002", "看综艺"),
      ("1003", "看八卦"),
      ("1004", "打游戏"),
      ("1009", "学习")
    ))

    /**
     * join 内连接
     * right join 右连接
     * left join 左连接
     * full join 全连接
     */

    //内连接
    val resRDD1: RDD[(String, (String, String))] = rdd1.join(rdd2)
    val resRDD2: RDD[(String, String, String)] = resRDD1.map {
      case (id: String, (name: String, like: String)) =>
        (id, name, like)
    }
//    resRDD2.foreach(println)

    //右连接
    val resRDD3: RDD[(String, (Option[String], String))] = rdd1.rightOuterJoin(rdd2)
    val resRDD4: RDD[(String, String, String)] = resRDD3.map {
      case (id: String, (Some(name), like: String)) =>
        (id, name, like)
      case (id: String, (None, like: String)) =>
        (id, "查无此人", like)
    }
//    resRDD4.foreach(println)

    //左连接
    val resRDD5: RDD[(String, (String, Option[String]))] = rdd1.leftOuterJoin(rdd2)
    val resRDD6: RDD[(String, String, String)] = resRDD5.map {
      case (id: String, (name: String, Some(like))) =>
        (id, name, like)
      case (id: String, (name: String, None)) =>
        (id, name, "看美女")
    }
    resRDD6.foreach(println)

    //全连接
    val resRDD7: RDD[(String, (Option[String], Option[String]))] = rdd1.fullOuterJoin(rdd2)
    val resRDD8: RDD[(String, String, String)] = resRDD7.map {
      case (id: String, (Some(name), Some(like))) =>
        (id, name, like)
      case (id: String, (Some(name), None)) =>
        (id, name, "偷看美女")
      case (id: String, (None, Some(like))) =>
        (id, "查无此人", like)
    }
    resRDD8.foreach(println)
  }
}

5.10、转换算子:MapValues

  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
      .setMaster("local")
      .setAppName("MapValues算子演示")
    val sc: SparkContext = new SparkContext(conf)

    val linesRDD: RDD[String] = sc.textFile("spark/data/students.txt")
    val kvRDD: RDD[(String, Int)] = linesRDD.map(_.split(",")).map {
      case Array(_, name: String, age: String, _, _) =>
        (name, age.toInt)
    }
    /**
     * mapValues函数也是作用在kv格式的算子上
     * 将每个元素的值传递给后面的函数,进行处理得到新的值,键不变,这个处理的组合重新的返回到新的RDD中
     */
    kvRDD.mapValues(_+100).foreach(println)

  }
}

5.11、转换算子:partitionBy

object Demo11PartitionBy {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
      .setMaster("local")
      .setAppName("partitionBy算子演示")

    val sc: SparkContext = new SparkContext(conf)

    val linesRDD: RDD[String] = sc.textFile("spark/data/wcs/*")

    /**
     * mapPartitions:一次处理一个分区中的数据
     * 他与map的区别在于,map是每次处理一条数据就返回一条数据到下一个rdd
     * 而mapPartitions一次处理一个分区的数据,处理完再返回
     * 最后的处理结果和map处理效果一样的
     *
     * mapPartition可以优化与数据库链接的次数
     */
    val rdd1: RDD[String] = linesRDD.mapPartitions((itr: Iterator[String]) => {
      println("=========================================")
      itr.map((e: String) => {
        e
      })
    })

    rdd1.foreach(println)
  }
}

5.12、转换算子:SortBy

  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setMaster("local").setAppName("sortBy算子演示")

    val sc: SparkContext = new SparkContext(conf)
    val rdd1: RDD[Int] = sc.parallelize(List(
      12, 34, 56, 67, 32, 27, 76, 48, 51, 124
    ))
    val rdd2: RDD[Int] = rdd1.sortBy((e: Int) => -e)
    rdd2.foreach(println)
  }

六、行动算子

6.1、行动算子:Foreach

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object DemoForeach {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setMaster("local")
      .setAppName("foreach")
    val sc: SparkContext = new SparkContext(conf)

    val linesRDD: RDD[String] = sc.textFile("spark/data/students.txt")

    val rdd1: RDD[Array[String]] = linesRDD.map((line: String) => line.split(","))

    val rdd2: RDD[(String, String, String, String, String)] = rdd1.map {
      case Array(id: String, name: String, age: String, gender: String, clazz: String) =>
        (id, name, age, gender, clazz)
    }

    /**
     * 行动算子,就可以触发一次作业执行,有几次行动算子调用,就会触发几次
     *
     * rdd是懒加载的性质
     */
//    stuRDD.foreach(println)

    println("--------------------------------")
    val rdd3: RDD[(String, String, String, String, String)] = rdd2.map((t5: (String, String, String, String, String)) => {
      println("=============================")
      t5
    })
    rdd3.foreach(println)

    while (true){

    } 

  }
}

6.2、行动算子:collect

  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
      .setMaster("local")
      .setAppName("collect算子演示")

    val sc: SparkContext = new SparkContext(conf)

    val linesRDD: RDD[String] = sc.textFile("spark/data/students.txt")

    val rdd1: RDD[Array[String]] = linesRDD.map((e: String) => e.split(","))

    val rdd2: RDD[Student] = rdd1.map {
      case Array(id: String, name: String, age: String, gender: String, clazz: String) =>
        Student(id.toInt, name, age.toInt, gender, clazz)
    }
    //collect将rdd转成合适的scala中的数据结构
    val stuArray: Array[Student] = rdd2.collect()
    //foreach是scala中的foreach,不会产生作业执行的
    stuArray.foreach(println)
    while (true){

    }
  }

}
case class Student(id:Int,name:String,age:Int,gender:String,clazz:String)

七、spark缓存

/**
 * 缓存:
 * 缓存的目的是为了spark core作业执行的时候,缩短rdd的执行链,能够更快的得到结果
 * 缓存的实现方式:
 * 1、需要缓存的rdd调用cache函数
 * 2、persist(StorageLevel.MEMORY_ONLY) 修改缓存级别
 */
object Demo16Cache {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
      .setMaster("local")
      .setAppName("缓存演示")
    val sc: SparkContext = new SparkContext(conf)

    val linesRDD: RDD[String] = sc.textFile("spark/data/students.txt")
    val stuRDD: RDD[Student2] = linesRDD.map(_.split(",")).map {
      case Array(id: String, name: String, age: String, gender: String, clazz: String) =>
        Student2(id, name, age.toInt, gender, clazz)
    }
    //需求1:求每个班级的人数
    val rdd1: RDD[(String, Iterable[Student2])] = stuRDD.groupBy(_.clazz)
    val resRDD1: RDD[(String, Int)] = rdd1.map((kv: (String, Iterable[Student2])) => (kv._1, kv._2.size))
    resRDD1.foreach(println)

    //需求1:求每个年龄的人数
    val rdd2: RDD[(Int, Iterable[Student2])] = stuRDD.groupBy(_.age)
    val resRDD2: RDD[(Int, Int)] = rdd2.map((kv: (Int, Iterable[Student2])) => (kv._1, kv._2.size))
    resRDD2.foreach(println)

    while (true){

    }
  }
}
case class Student2(id:String,name:String,age:Int,gender:String,clazz:String)

八、checkPoint

/**
 * 永久将执行过程中RDD中流动的数据存储到磁盘(hdfs)中
 * checkpoint
 *
 * 需要设置checkpoint的路径,统一设置的
 *
 * checkpoint也相当于一个行动算子,触发作业执行
 * 第二次DAG有向无环图执行的时候,直接从最后一个有检查点的rdd开始向下执行
 */
object Demo17Checkpoint {
    def main(args: Array[String]): Unit = {
      val conf: SparkConf = new SparkConf()
        .setMaster("local")
        .setAppName("checkpoint")
      val sc: SparkContext = new SparkContext(conf)

      //设置检查点存储路径
      sc.setCheckpointDir("spark/data/checkpoint1")

      val linesRDD: RDD[String] = sc.textFile("spark/data/students.txt")
      val studentRDD: RDD[Student2] = linesRDD.map(_.split(",")).map {
        case Array(id: String, name: String, age: String, gender: String, clazz: String) =>
          Student2(id, name, age.toInt, gender, clazz)
      }

      studentRDD.checkpoint()
      //需求1:求每个班级的人数
      val rdd1: RDD[(String, Iterable[Student2])] = studentRDD.groupBy(_.clazz)
      val resRDD1: RDD[(String, Int)] = rdd1.map((kv: (String, Iterable[Student2])) => (kv._1, kv._2.size))
      resRDD1.foreach(println)

      //需求2:求每个年龄的人数
      val rdd2: RDD[(Int, Iterable[Student2])] = studentRDD.groupBy(_.age)
      val resRDD2: RDD[(Int, Int)] = rdd2.map((kv: (Int, Iterable[Student2])) => (kv._1, kv._2.size))
      resRDD2.foreach(println)

      while (true) {

      }
  }

}

九、spark独立运行模式

object Demo18Standalone {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
//      .setMaster("local")//在集群运行关闭(注释)本地运行打开
      .setAppName("standalone集群运行")

    val sc: SparkContext = new SparkContext(conf)

    //统计单词个数
    val rdd1: RDD[String] = sc.parallelize(List("python|java|redis", "hadoop|hbase|hive|dataX", "scala|spark|clickhouse|flinkX"))
    rdd1.flatMap(_.split("\\|"))
      .map((_,1))
      .reduceByKey(_+_)
      .foreach(println)

    /**
     * standalone
     *  - client模式提交命令:(本地)
     *    spark-submit --class com.shujia.core.Demo18Standalone --master spark://master:7077 --executor-memory 512m --total-executor-cores 1 spark-1.0.jar 10
     *
     *  - cluster模式提交命令:(集群)
     *    spark-submit --class com.shujia.core.Demo18Standalone --master
     *    spark://master:7077 --executor-memory 512M --total-executor-cores 1 --deploy-mode cluster spark-1.0.jar 10
     */
  }

十、(spark)Yarn运行模式

object Demo19YarnCluster {
  def main(args: Array[String]): Unit = {
    //读取hdfs上的学生数据,统计每个班级的人数,写到hdfs上

    val conf: SparkConf = new SparkConf().setAppName("yarnCluster")
    val sc: SparkContext = new SparkContext(conf)

    //打包到集群,路径就是hdfs路径
    //如果是local的话,路径就是windows的路径

    val linesRDD: RDD[String] = sc.textFile("/bigdata30/students.csv")

//    val linesRDD2: RDD[String] = linesRDD.coalesce(1)
//    linesRDD2.repartition(1)//设置分区数

    
    println(s"=======================linesRDD的分区数是: ${linesRDD.getNumPartitions} =======================")
   
    val clazzKVRDD: RDD[(String, Int)] = linesRDD.map((line: String) => {
      line.split(",") match {
        case Array(_, _, _, _, clazz: String) =>
          (clazz, 1)
      }
    })

    val resultRDD: RDD[(String, Int)] = clazzKVRDD.reduceByKey(_ + _)
    val resultRDD2: RDD[String] = resultRDD.map((t2: (String, Int)) => s"${t2._1},${t2._2}")

    println("=======================================================")
    println(s"======================= resultRDD2的分区数是: ${resultRDD2.getNumPartitions} =======================")
    println("=======================================================")

    //行动算子,触发作业执行
    resultRDD2.saveAsTextFile("/bigdata30/sparkOut1")
  }
  //spark-submit --class com.shujia.core.Demo19YarnCluster --master yarn --deploy-mode cluster spark-1.0.jar
 }

}

十一、类加载器:Accumulator

object DemoAccumulator {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf()
      .setMaster("local")
      .setAppName("类加载器案列")

    val sc: SparkContext = new SparkContext(conf)

    val linesRDD: RDD[String] = sc.textFile("spark/data/students.txt")
    var num =0

    /**
     * 累加器
     * 必要有行动算子触发作业执行
     */
    //创建累加器变量
//    val c1: LongAccumulator = sc.longAccumulator("c1")
//
//    linesRDD.foreach((e:String)=>{
//      num+=1
//      println("----------------")
//      println(num)
//    })
//    println(s"num的值为:$num") // 0

    //使用累加器
    val c1: LongAccumulator = sc.longAccumulator("c1")
    linesRDD.foreach((e:String)=>{
      c1.add(1)
    })
    println(s"累加之后的值为:${c1.value}")


    //使用累加器
    val c2: LongAccumulator = sc.longAccumulator("c2")
    linesRDD.map((e:String)=>{
      c2.add(1)
    }).collect()
    println(s"累加之后的值为:${c2.value}")

    /**
     * 写spark core程序的注意事项
     * 1、RDD中无法嵌套使用RDD
     * 2、RDD中无法使用SparkContext
     */
  }
}

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值