大数据技术Spark之Spark Core(三)

大数据技术Spark之Spark Core(三)

一:action

reduce(func) :作用: 通过 func 函数聚集 RDD 中的所有元素,先聚合分区内数据,再聚合分区间数据。
collect():作用: 在驱动程序中,以数组的形式返回数据集的所有元素。
count():作用: 返回 RDD 中元素的个数
first():作用:返回RDD中的第一个元素
take(n):作用:返回一个由RDD的n个元素组成的数组
takeOrdered(n):作用:返回改RDD排序后的前n个元素组成的数组
aggregate:作用: aggregate 函数将每个分区里面的元素通过 seqOp 和初始值进行聚合,然后用
combine 函数将每个分区的结果和初始值(zeroValue)进行 combine 操作。这个函数最终返回
的类型不需要和 RDD 中元素类型一致。
fold(num)(func): 作用: 折叠操作, aggregate 的简化操作, seqop 和 combop 一样
saveAsTextFile(path):作用: 将数据集的元素以 textfile 的形式保存到 HDFS 文件系统或者其他支持的文件系统,对于每个元素, Spark 将会调用 toString 方法,将它装换为文件中的文本。
saveAsSequenceFile(path):作用: 将数据集中的元素以 Hadoop sequencefile 的格式保存到指定的目录下,可以使 HDFS或者其他 Hadoop 支持的文件系统
countByKey():作用: 针对(K,V)类型的 RDD,返回一个(K,Int)的 map,表示每一个 key 对应的元素个数。
foreach(func):作用:在数据集的每一个元素上运行函数func进行更新

二:RDD中的函数传递

​ 在实际开发中我们往往需要自己定义一些对于 RDD 的操作,那么此时需要主要的是,初始化工作是在 Driver 端进行的,而实际运行程序是在 Executor 端进行的,这就涉及到了跨进程通信,是需要序列化的。 下面我们看几个例子

package com.ityouxin.action

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

class Search(query:String) extends Serializable {
  def isMatch(s:String):Boolean={
    s.contains(query)
  }
  def getMatch1(rdd:RDD[String]):RDD[String]={
    rdd.filter(this.isMatch)
  }
  def getMatch2(rdd:RDD[String]):RDD[String]={
    rdd.filter(x=>x.contains(query))
  }
}
object SeriTest{
  def main(args: Array[String]): Unit = {
    val config: SparkConf = new SparkConf()
      .setAppName("Spark_Study")
      .setMaster("local[*]") //本地模式
    val sc =  new SparkContext(config)
    val rdd1 = sc.parallelize(Array("hadoop", "spark", "hive", "ityouxin"))
    val search = new Search("oop")
    val rdd2 = search.getMatch1(rdd1)
    println(rdd2.collect().mkString(","))
    val rdd3: RDD[String] = search.getMatch2(rdd1)
    println(rdd3.collect().mkString(","))
  }
}

三:RDD的依赖关系

​ 窄依赖

​ 窄依赖指的是每一个父 RDD 的 Partition 最多被子 RDD 的一个 Partition 使用,窄依赖我们形象的比喻为独生子女

​ 宽依赖

​ 宽依赖指的是多个子 RDD 的 Partition 会依赖同一个父 RDD 的 Partition,会引起 shuffle,总结: 宽依赖我们形象的比喻为超生

​ DAG:

​ DAG(Directed Acyclic Graph)叫做有向无环图,原始的 RDD 通过一系列的转换就就形成了 DAG,根据 RDD 之间的依赖关系的不同将 DAG 划分成不同的 Stage,对于窄依赖,partition 的转换处理在 Stage 中完成计算。对于宽依赖,由于有 Shuffle 的存在,只能在 parentRDD 处理完成后,才能开始接下来的计算,因此宽依赖是划分 Stage 的依据 。

​ 任务划分(面试重点)

RDD 任务切分中间分为: Application、 Job、 Stage 和 Task

1) Application:初始化一个 SparkContext 即生成一个 Application
2) Job:一个 Action 算子就会生成一个 Job
3) Stage: 根据 RDD 之间的依赖关系的不同将 Job 划分成不同的 Stage, 遇到一个宽依赖则
划分一个 Stage。

4) Task: Stage 是一个 TaskSet, 将 Stage 划分的结果发送到不同的 Executor 执行即为一个
Task。
注意: Application->Job->Stage-> Task 每一层都是 1 对 n 的关系。

​ RDD缓存

​ RDD通过persist方法或cache方法可以将前面的计算结果缓存, 默认情况下 persist() 会把数据以序列化的形式缓存在 JVM 的堆空间中。但是并不是这两个方法被调用时立即缓存,而是触发后面的 action 时, 该 RDD 将会被缓存在计算节点的内存中,并供后面重用。

四:数据读取和保存

​ Spark 的数据读取及数据保存可以从两个维度来作区分:文件格式以及文件系统。

文件格式分为: Text 文件、 Json 文件、 Csv 文件、 Sequence 文件以及 Object 文件;
文件系统分为:本地文件系统、 HDFS、 HBASE 以及数据库。

  1. text文件类型的数据

    读取:textFile(String) 保存:saveAsTextFile(String)

    1. Json文件

    如果 JSON 文件中每一行就是一个 JSON 记录,那么可以通过将 JSON 文件当做文本
    文件来读取,然后利用相关的 JSON 库对每一条数据进行 JSON 解析。
    注意:使用 RDD 读取 JSON 文件处理很复杂,同时 SparkSQL 集成了很好的处理 JSON
    文件的方式,所以应用中多是采用 SparkSQL 处理 JSON 文件。

    读取文件:val json = sc.textFile("/people.json")

    解析json数据:val result = json.map(JSON.parseFull)

    1. Sequence 文件

    SequenceFile 文件是 Hadoop 用来存储二进制形式的 key-value 对而设计的一种平面文
    件(Flat File)。 Spark 有专门用来读取 SequenceFile 的接口。在 SparkContext 中,可以调用
    sequenceFile keyClass, valueClass
    注意: SequenceFile 文件只针对 PairRDD

    保存RDD:scala> rdd.saveAsSequenceFile(“file:///opt/module/spark/seqFile”)

    读取文件:val seq = sc.sequenceFileInt,Int

  2. HDFS

    Spark 的整个生态系统与 Hadoop 是完全兼容的,所以对于 Hadoop 所支持的文件类型或者数据库类型,Spark 也同样支持.另外,由于 Hadoop 的 API 有新旧两个版本,所以 Spark 为了能够兼容 Hadoop 所有的版本,也提供了两套创建操作接口.对于外部存储创建操作而言,hadoopRDD 和 newHadoopRDD 是最为抽象的两个函数接口,主要包含以下四个参数.
    1) 输入格式(InputFormat): 制定数据输入的类型,如 TextInputFormat 等,新旧两个版本所引用的版本分别是 org.apache.hadoop.mapred.InputFormat 和
    org.apache.hadoop.mapreduce.InputFormat(NewInputFormat)
    2) 键类型: 指定[K,V]键值对中 K 的类型
    3) 值类型: 指定[K,V]键值对中 V 的类型
    4) 分区值: 指定由外部存储生成的 RDD 的 partition 数量的最小值,如果没有指定,系统
    会使用默认值 defaultMinSplits

    注意:其他创建操作的 API 接口都是为了方便最终的 Spark 程序开发者而设置的,是这两个接口的高效实现版本.例如,对于 textFile 而言,只有 path 这个指定文件路径的参数,其他参数在系统内部指定了默认值。
    1.在 Hadoop 中以压缩形式存储的数据,不需要指定解压方式就能够进行读取,因为Hadoop 本身有一个解压器会根据压缩文件的后缀推断解压算法进行解压.
    2.如果用 Spark 从 Hadoop 中读取某种类型的数据不知道怎么读取的时候,上网查找一个
    使用 map-reduce 的时候是怎么读取这种数据的,然后再将对应的读取方式改写成上面的
    hadoopRDD 和 newAPIHadoopRDD 两个类就行了

  3. MySQL数据库连接

    支持通过 Java JDBC 访问关系型数据库。需要通过 JdbcRDD 进行,示例如下:

    1. 添加依赖
    <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <version>5.1.27</version>
    </dependency>
    2. mYSQL读取
    class MyAvg {
      var spark:SparkSession = null
      @Before
      def init={
        spark = SparkSession.builder().appName("sparkSql").master("local[*]").getOrCreate()
      }
      @Test
      def sqlDataSource={
        //load 默认的加载文件的格式由参数spark.sql.source.default决定
        val df = spark.read.load("datas/users.parquet")
        df.show()
       // spark.sql("select * from parquet.'datas/users.parquet'").show()
        //spark.sql("select * from json.'datas/people.json'").show()
      //jdbc
        spark.read.format("jdbc")
          .option("url","jdbc:mysql://localhost:3306/day10")
          .option("dbtable","user")
          .option("user","root")
          .option("password","123")
          .load().show()
        println("-------------------")
        val option = new Properties
        option.setProperty("user","root")
        option.setProperty("password","123")
        spark.read.jdbc("jdbc:mysql://localhost:3306/day10","user",option).show()
      }
    
  4. HBASE数据库

    由于 org.apache.hadoop.hbase.mapreduce.TableInputFormat 类的实现, Spark 可以通过
    Hadoop 输入格式访问 HBase。这个输入格式会返回键值对数据,其中键的类型为 org.
    apache.hadoop.hbase.io.ImmutableBytesWritable,而值的类型为 org.apache.hadoop.hbase.client.
    Result。

    package com.ityouxin.hbase
    
    import org.apache.hadoop.hbase.HBaseConfiguration
    import org.apache.hadoop.hbase.client.{Put, Result}
    import org.apache.hadoop.hbase.io.ImmutableBytesWritable
    import org.apache.hadoop.hbase.mapred.TableOutputFormat
    import org.apache.hadoop.hbase.mapreduce.TableInputFormat
    import org.apache.hadoop.hbase.util.Bytes
    import org.apache.hadoop.mapred.JobConf
    import org.apache.spark.rdd.RDD
    import org.apache.spark.{SparkConf, SparkContext}
    
    object Spark_Hbase {
      def main(args: Array[String]): Unit = {
        val conf = new SparkConf().setMaster("local[*]").setAppName("hbase")
        val sc = new SparkContext(conf)
        val datas = sc.makeRDD(List(("1","2","3"),("11","22","33")))
        val rdd2 = datas.map{
          case(rowkey,ename,salay) =>
            val put = new Put(Bytes.toBytes(rowkey))
            put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("ename"),Bytes.toBytes(ename))
            put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("sal"),Bytes.toBytes(salay))
            (new ImmutableBytesWritable,put)
        }
        val hbaseConf = HBaseConfiguration.create
        hbaseConf.set(TableOutputFormat.OUTPUT_TABLE,"hbase_emp_table")
        val jobConf:JobConf = new JobConf(hbaseConf)
        jobConf.setOutputFormat(classOf[TableOutputFormat])
        rdd2.saveAsHadoopDataset(jobConf)
        //注意netty包的冲突,通过执行mvn   dependncy:tree   来进行查找相应jar包,然后排出
    
        //读Hbase表
        hbaseConf.set(TableInputFormat.INPUT_TABLE,"hbase_emp_table")
        val ReadRdd: RDD[(ImmutableBytesWritable, Result)] =
          sc.newAPIHadoopRDD(hbaseConf,classOf[TableInputFormat],classOf[ImmutableBytesWritable],classOf[Result])
        sc.stop()
      }
    }
    
    
  5. RDD编程进阶

    1. 累加器

      累加器用来对信息进行聚合,通常在向 Spark 传递函数时,比如使用 map() 函数或者用 filter() 传条件时,可以使用驱动器程序中定义的变量,但是集群中运行的每个任务都会得到这些变量的一份新的副本,更新这些副本的值也不会影响驱动器中的对应变量。 如果我们想实现所有分片处理时更新共享变量的功能,那么累加器可以实现我们想要的效果。

    2. 系统累加器

      val notice = sc.textFile("./NOTICE")

      val blanklines = sc.accumulator(0)

      累加器的用法如下所示。
      通过在驱动器中调用 SparkContext.accumulator(initialValue)方法,创建出存有初始值的
      累加器。返回值为 org.apache.spark.Accumulator[T] 对象,其中 T 是初始值 initialValue 的
      类型。 Spark 闭包里的执行器代码可以使用累加器的 += 方法(在 Java 中是 add)增加累加器
      的值。 驱动器程序可以调用累加器的 value 属性(在 Java 中使用 value()或 setValue())来访问
      累加器的值。
      注意: 工作节点上的任务不能访问累加器的值。从这些任务的角度来看,累加器是一个只写
      变量。
      对于要在行动操作中使用的累加器, Spark 只会把每个任务对各累加器的修改应用一次。
      因此,如果想要一个无论在失败还是重复计算时都绝对可靠的累加器,我们必须把它放在
      foreach() 这样的行动操作中。转化操作中累加器可能会发生不止一次更新

    3. 自定义累加器

      自定义累加器类型的功能在 1.X 版本中就已经提供了,但是使用起来比较麻烦,在 2.0版本后,累加器的易用性有了较大的改进,而且官方还提供了一个新的抽象类:AccumulatorV2 来提供更加友好的自定义类型累加器的实现方式。实现自定义类型累加器需要继承 AccumulatorV2 并至少覆写下例中出现的方法,下面这个累加器可以用于在程序运行过程中收集一些文本类信息,最终以Set[String]的形式返回。 1

      package com.ityouxin
      
      import org.apache.spark.{SparkConf, SparkContext}
      import org.apache.spark.util.AccumulatorV2
      
      object accumulator {
        def main(args: Array[String]): Unit = {
          val conf:SparkConf = new SparkConf().setMaster("local[*]").setAppName("accumulator")
          val sc = new SparkContext(conf)
          val rdd1 = sc.makeRDD(List(1,2,3,4,5,6),2)
          val sum = new Myacc
          sc.register(sum)
          rdd1.foreach(i=>{
            sum.sum =sum.sum+i
          })
          println(sum.sum)
          sc.stop()
        }
      }
      class Myacc extends AccumulatorV2[Int,Int]{
        var sum = 0
        override def isZero: Boolean = {
          if (sum==0)true else false
        }
      
        override def copy(): AccumulatorV2[Int, Int] = {
          val acc =new Myacc
          acc.sum=this.sum
          acc
        }
      
        override def reset(): Unit = {
          this.sum=0
        }
      
        override def add(v: Int): Unit = {
          this.sum = this.sum +v
        }
      
        override def merge(other: AccumulatorV2[Int, Int]): Unit = {
          this.sum = this.sum+other.value
        }
      
        override def value: Int = {
          this.sum
        }
      }
      
    4. 自定义累加器案例(二)

      package com.ityouxin
      
      import java.util
      
      import org.apache.spark.util.AccumulatorV2
      import org.apache.spark.{SparkConf, SparkContext}
      
      //过滤掉字母
      object Spark_Accumulator {
        def main(args: Array[String]): Unit = {
          val conf = new SparkConf().setMaster("local[*]").setAppName("hbase")
          val sc = new SparkContext(conf)
      
          val accumulator = new LogAccumulator
          sc.register(accumulator)
          //rdd,过滤掉带字母的元素
          val sum =sc.makeRDD(Array(("1"),("2a"),("33"),("7lhx"),("5")),2).filter(
            line=>{
              //正则表达书,匹配带字母的元组
             val pattern = """^-?(\d+)"""
             val flag =line.matches(pattern)
              //当flag匹配到字母后,将字段进行调用LogAccumulator.class类的add方法进行处理
             if (!flag){
              accumulator.add(line)
             }
              flag//进行map映射转换,然后reduce算子实现过滤后的value相加
      
           }).map(_.toInt).reduce(_+_)
          println("sum : " + sum)
          val str: util.Iterator[String] = accumulator.value.iterator()
          while (str.hasNext){
            println(str.next())
          }
        }
      class LogAccumulator extends AccumulatorV2[String,java.util.Set[String]]{
        private val  _logArray:java.util.Set[String] = new java.util.HashSet[String]()
        override def isZero: Boolean = {
          _logArray.isEmpty
        }
      
        override def copy():org.apache.spark.util.AccumulatorV2[String, java.util.Set[String]] = {
          val accumulator = new LogAccumulator()
          accumulator.synchronized(
            accumulator._logArray.addAll(_logArray)
          )
          accumulator
        }
      
        override def reset(): Unit = {
          _logArray.clear()
        }
      
        override def add(v: String): Unit = {
          _logArray.add(v)
        }
      
        override def merge(other: org.apache.spark.util.AccumulatorV2[String, java.util.Set[String]]): Unit = {
          other match {
            case o:LogAccumulator => _logArray.addAll(o.value)
          }
        }
      
        override def value: java.util.Set[String] = {
          java.util.Collections.unmodifiableSet(_logArray)
        }
      }
      }
      
    5. 广播变量(调优策略)

      广播变量用来高效分发较大的对象。向所有工作节点发送一个较大的只读值,以供一个或多个 Spark 操作使用。比如,如果你的应用需要向所有节点发送一个较大的只读查询表,甚至是机器学习算法中的一个很大的特征向量,广播变量用起来都很顺手。 在多个并行操作中使用同一个变量,但是Spark 会为每个任务分别发送 。

      使用广播变量的过程如下:
      (1) 通过对一个类型 T 的对象调用 SparkContext.broadcast 创建出一个 Broadcast[T]对象。 任何可序列化的类型都可以这么实现。
      (2) 通过 value 属性访问该对象的值(在 Java 中为 value() 方法)。
      (3) 变量只会被发到各个节点一次,应作为只读值处理(修改这个值不会影响到别的节点)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spark-Core文档是本人经年总结笔记汇总而来,对于自我学习Spark核心基础知识非常方便,资料例举完善,内容丰富。具体目录如下: 目录 第一章 Spark简介与计算模型 3 1 What is Spark 3 2 Spark简介 3 3 Spark历史 4 4 BDAS生态系统 4 5 Spark与Hadoop的差异 5 6 Spark的适用场景 6 7 Spark成功案例 6 第二章 Spark开发环境搭建 8 1 Spark运行模式 8 2 Spark环境搭建 8 2.1Scala的安装 8 2.2Spark的单节点配置 9 2.3Spark-Standalone集群配置 9 2.4Spark-on-Yarn模式配置 12 2.5Spark-on-Mesos模式配置 13 2.6Hive-on-Spark配置 13 第Spark计算模型 15 1 RDD编程 15 1.1弹性分布式数据集RDD 15 1.2构建RDD对象 15 2RDD操作 15 2.1将函数传递给Spark 16 2.2了解闭包 16 2.3Pair RDD模型 17 2.4Spark常见转换操作 18 2.5Spark常见行动操作 20 2.6RDD持久化操作 21 2.7注意事项 23 2.7并行度调优 24 2.8分区方式 25 3Examle:PageRank 27 第四章 Spark编程进阶 29 1共享变量 29 1.1累加器 30 1.2广播变量 31 2基于分区进行操作 32 3与外部程序间的管道 33 4数值RDD的操作 34 5 Spark Shuffle机制 34 第五章 Spark调优与调试 39 1开发调优: 40 1.1调优概述 40 1.2原则一:避免创建重复的RDD 40 1.3原则二:尽可能复用同一个RDD 41 1.4原则:对多次使用的RDD进行持久化 42 1.5原则四:尽量避免使用shuffle算子 43 1.6原则五:使用map-side预聚合的shuffle操作 44 1.7原则六:使用高性能的算子 45 1.8原则七:广播大变量 46 1.9原则八:使用Kryo优化序列化性能 47 1.10原则九:优化数据结构 48 2资源调优 48 2.1调优概述 48 2.2 Spark作业基本运行原理 49 2.3资源参数调优 50 第六章 Spark架构和工作机制 52 1 Spark架构 52 1.1 Spark架构组件简介 52 1.2 Spark架构图 54 2 Spark工作机制 54 2.1 Spark作业基本概念 54 2.2 Spark程序与作业概念映射 55 2.3 Spark作业运行流程 55 3 Spark工作原理 55 3.1 作业调度简介 55 3.2 Application调度 56 3.3 Job调度 56 3.4 Tasks延时调度 56 第七章 Spark运行原理 57 1 Spark运行基本流程 57 2 Spark在不同集群的运行架构 58 2.1 Spark on Standalone运行过程 59 2.2 Spark on YARN运行过程 60
Spark CoreSpark的核心组件,主要负责任务调度、内存管理、错误恢复、与存储系统的交互等。以下是大数据常见面试题之Spark Core: 1. 什么是Spark CoreSpark CoreSpark的核心组件,它提供了分布式任务调度、内存管理、错误恢复、与存储系统的交互等功能。 2. Spark Core的作用是什么? Spark Core的作用是管理Spark应用程序的整个生命周期,包括任务调度、内存管理、错误恢复、与存储系统的交互等。 3. Spark Core的优点是什么? Spark Core的优点包括高效的内存管理、快速的任务调度、灵活的错误恢复、与多种存储系统的兼容性等。 4. Spark Core如何实现任务调度? Spark Core通过DAG(有向无环图)来实现任务调度,将任务分解成多个阶段,每个阶段包含多个任务,然后按照依赖关系依次执行。 5. Spark Core如何实现内存管理? Spark Core通过RDD(弹性分布式数据集)来实现内存管理,将数据分成多个分区,每个分区可以在不同的节点上进行计算,从而实现高效的内存管理。 6. Spark Core如何实现错误恢复? Spark Core通过RDD的容错机制来实现错误恢复,当某个节点出现故障时,Spark会自动将该节点上的任务重新分配到其他节点上执行。 7. Spark Core如何与存储系统交互? Spark Core通过支持多种存储系统的API来与存储系统交互,包括HDFS、S3、Cassandra等。同时,Spark还提供了自己的内存存储系统——Tachyon。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值