sparksql入门总结

spark
    Spark是一种基于内存的快速、通用、可扩展的大数据分析计算引擎
    支持迭代式计算,图形计算,Spark框架计算比MR快的原因是:中间结果不落盘。注意Spark的Shuffle也是落盘的。
    Spark内置模块
        Spark Core:Spark的基本功能,含任务调度、内存管理、错误恢复、与存储系统交互等模块。Spark Core包含了对弹性分布式数据集(Resilient Distributed DataSet,简称RDD)的API定义。 
        Spark SQL:是Spark用来操作结构化数据的程序包。通过Spark SQL,我们可以使用 SQL或者Apache Hive版本的HQL来查询数据。Spark SQL支持多种数据源,比如Hive表、Parquet以及JSON等。
        Spark Streaming:是Spark提供的对实时数据进行流式计算的组件。提供了用来操作数据流的API,并且与Spark Core中的 RDD API高度对应。 
        Spark MLlib:提供常见的机器学习功能的程序库。包括分类、回归、聚类、协同过滤等,还提供了模型评估、数据 导入等额外的支持功能。 
        Spark GraphX:主要用于图形并行计算和图挖掘系统的组件。
        集群管理器:Spark设计为可以高效地在一个计算节点到数千个计算节点之间伸缩计算。为了实现这样的要求,同时获得最大灵活性,Spark支持在各种集群管理器(Cluster Manager)上运行,包括Hadoop YARN、Apache Mesos,以及Spark自带的一个简易调度器,叫作独立调度器。
    Spark运行模式
        1)Local模式:在本地部署单个Spark服务
        2)Standalone模式:Spark自带的任务调度模式。
        3)YARN模式:Spark使用Hadoop的YARN组件进行资源与任务调度。
        4)Mesos模式:Spark使用Mesos平台进行资源与任务的调度。
        
        Standalone模式
            /opt/module/spark-standalone/conf
            vim slaves 添加work节点
            修改spark-env.sh文件,添加master节点
                SPARK_MASTER_HOST=hadoop102
                SPARK_MASTER_PORT=7077
            分发spark-standalone包
            遇到 “JAVA_HOME not set” 异常,可以在sbin目录下的spark-config.sh 文件中加入java路径
            历史服务
            修改spark-default.conf文件,配置日志存储路径(写),并分发
                spark.eventLog.enabled          true
                spark.eventLog.dir              hdfs://hadoop102:8020/directory
            修改spark-env.sh文件
                export SPARK_HISTORY_OPTS="
                -Dspark.history.ui.port=18080 
                -Dspark.history.fs.logDirectory=hdfs://hadoop102:8020/directory 
                -Dspark.history.retainedApplications=30"
            配置高可用:依赖于zookeeper
                修改spark-env.sh文件
#注释掉如下内容:
#SPARK_MASTER_HOST=hadoop102
#SPARK_MASTER_PORT=7077

#添加上如下内容。配置由Zookeeper管理Master,在Zookeeper节点中自动创建/spark目录,用于管理:
export SPARK_DAEMON_JAVA_OPTS="
-Dspark.deploy.recoveryMode=ZOOKEEPER 
-Dspark.deploy.zookeeper.url=节点主机名1,节点主机名2,节点主机名3 
-Dspark.deploy.zookeeper.dir=/spark"

#添加如下代码
#Zookeeper3.5的AdminServer默认端口是8080,和Spark的WebUI冲突
export SPARK_MASTER_WEBUI_PORT=8989


        参数说明
        bin/spark-submit 
        #Spark程序中包含主函数的类
        --class org.apache.spark.examples.SparkPi 
        #Spark程序运行的模式,本地模式-->local[*]、Standalone模式-->spark://主机名:7077、Yarn
        --master spark://主机名:7077 
        #指定每个executor可用内存一般2-4g
        --executor-memory 2G 
        #指定所有executor使用的cpu核数
        --total-executor-cores 2 
        #打包好的应用jar,包含依赖。集群中放hdfs
        ./examples/jars/spark-examples_2.12-3.0.0.jar 
    
    Yarn模式
        修改/opt/module/spark-yarn/conf/spark-env.sh,添加YARN_CONF_DIR配置
            YARN_CONF_DIR=/opt/module/hadoop-3.1.3/etc/hadoop
    注:park2中jersey版本是2.22,但是yarn中还需要依赖1.9,版本不兼容
    yarn-site.xml中,添加
<property>
    <name>yarn.timeline-service.enabled</name>
    <value>false</value>
</property>
        配置历史服务
        修改spark-env.sh文件
export SPARK_HISTORY_OPTS="
-Dspark.history.ui.port=18080 
-Dspark.history.fs.logDirectory=hdfs://主机名:8020/directory 
-Dspark.history.retainedApplications=30"
        修改配置文件/opt/module/spark-yarn/conf/spark-defaults.conf
spark.yarn.historyServer.address=主机名:18080
spark.history.ui.port=18080
        运行
        yarn-client:Driver程序运行在客户端,适用于交互、调试,希望立即看到app的输出。
        yarn-cluster:Driver程序运行在由ResourceManager启动的APPMaster适用于生产环境。
        --deploy-mode client/cluster
        
    端口号:
        1)Spark查看当前Spark-shell运行任务情况端口号:4040
        2)Spark Master内部通信服务端口号:7077    (类比于Hadoop的8020(9000)端口)
        3)Spark Standalone模式Master Web端口号:8080(类比于Hadoop YARN任务运行情况查看端口号:8088)
        4)Spark历史服务器端口号:18080        (类比于Hadoop历史服务器端口号:19888)

---------------------------------->_SparkCore_<----------------------------
SparkCore
    RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象。
        1)一组分区(Partition),即是数据集的基本组成单位,标记数据是哪个分区的;
        2)一个计算每个分区的函数;
        3)RDD之间的依赖关系;
        4)一个Partitioner,即RDD的分片函数;控制分区的数据流向(键值对)
        5)一个列表,存储存取每个Partition的优先位置(preferred location)移动数据不如移动计算,除非资源不够。
rdd创建
        //1.创建SparkConf并设置App名称
        val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

        //2.创建SparkContext,该对象是提交Spark App的入口
        val sc: SparkContext = new SparkContext(conf)

        //3.使用parallelize()创建rdd
        val rdd: RDD[Int] = sc.parallelize(Array(...),分区数)

        //4.使用makeRDD()创建rdd
        val rdd1: RDD[Int] = sc.makeRDD(Array(...),分区数)
        //读取文件。如果是集群路径:hdfs://主机名:9000/input
        val lineWordRdd: RDD[String] = sc.textFile("input",分区数)
Transformation转换算子
    单Value
        map()映射:一进一出,一次处理一个元素
        mapPartitions():以分区为单位执行Map,每次处理一个分区的数据,分区的数据处理完后,原RDD中分区的数据才释放,可能导致OOM。
        mapPartitionsWithIndex():比mapPartitions多一个整数参数表示分区号
        flatMap()扁平化
        glom():将RDD中每一个分区变成一个数组,并放置在新的RDD中,数组中元素的类型与原分区中元素类型一致
        groupBy()分组
            groupBy会存在shuffle过程
            shuffle:将不同的分区数据进行打乱重组的过程
            shuffle一定会落盘
        filter():过滤,返回值类型为true,则该元素会被添加到新的RDD中。
        sample():采样
            // withReplacement: true为有放回的抽样,false为无放回的抽样;
            // fraction表示:以指定的随机种子随机抽样出数量为fraction的数据;
            // seed表示:指定随机数生成器种子。
            抽取数据不放回(伯努利算法):sample(false, 0.5)-->范围在[0,1]之间,0:全不取;1:全取
            抽取数据放回(泊松算法):sample(true, 2)-->范围大于等于0.表示每一个元素被期望抽取到的次数
        distinct():去重
            distinct():默认情况下,distinct会生成与原RDD分区个数一致的分区数,对内部的元素去重,并将去重后的元素放到新的RDD中。
            注:用分布式的方式去重比HashSet集合方式不容易oOM
            distinct(2):去重后修改分区个数,对RDD采用多个Task去重,提高并发度
        coalesce():合并分区
            coalesce(2)默认不执行Shuffle方式,缩减分区数,用于大数据集过滤后,提高小数据集的执行效率
            coalesce(2, true)执行Shuffle方式
            假如求shuffle后,分区o中所有数据的和,需要等待读取所有分区的数据后,才能求和。如果数据一直放在内存中,容易导致oOM
            解决办法:Shuffle,必须要落盘等待数据的到来
        repartition():重新分区(执行Shuffle)
            内部其实执行的是coalesce操作,参数shuffle的默认值为true。
        注:coalesce一般为缩减分区,如果扩大分区,不使用shuffle是没有意义的,repartition扩大分区执行shuffle。
        sortBy():排序,默认为正序排列
            排序之前,将数据通过f函数进行处理,之后按照处理结果进行排序,默认正序。排序后新产生的RDD的分区数与原分区数一致。
            sortBy(num => num, false),倒序排序
        pipe():调用脚本
            针对每个分区,都调用一次shell脚本,返回输出的RDD
            pipe("脚本路径")注:脚本需要放Worker节点可以访问到的位置
    双Value
        intersection():交集
            rdd1.intersection(rdd2):对源RDD和参数RDD求交集后返回一个新的RDD
        union():并集
            rdd1.union(rdd2):对源RDD和参数RDD求并集后返回一个新的RDD
        subtract():差集
            rdd.subtract(rdd1):去除两个RDD中相同元素,不同的RDD将保留下来
        zip():拉链
            将两个RDD中的元素,以键值对的形式进行合并。其中,键值对中的Key为第1个RDD中的元素,Value为第2个RDD中的元素。
            默认两个RDD的partition数量以及元素数量都相同,元素个数不同,不能拉链,分区数不同,不能拉链
    Key-Value类型
        partitionBy():按照K重新分区
            将RDD[K,V]中的K按照指定Partitioner重新进行分区
            partitionBy(new org.apache.spark.HashPartitioner(2))对RDD重新分区
            自定义分区
                extends Partitioner
                1)numPartitions: Int:返回创建出来的分区数。
                2)getPartition(key: Any): Int:返回给定键的分区编号(0到numPartitions-1)。 
                3)equals():Java 判断相等性的标准方法。实现非常重要,用这个方法来检查分区器对象是否和其他分区器实例相同,Spark才可以判断两个RDD的分区方式是否相同
        reduceByKey():按照K聚合V
            将RDD[K,V]中的元素按照相同的K对V进行聚合。其存在多种重载形式,还可以设置新RDD的分区数。\
            reduceByKey((v1,v2) => v1+v2):计算相同key对应值的相加结果
        groupByKey()按照K重新分组
            对每个key进行操作,但只生成一个seq,并不进行聚合。该操作可以指定分区器或者分区数(默认使用HashPartitioner)
        reduceByKey和groupByKey区别
            1)reduceByKey:按照key进行聚合,在shuffle之前有combine(预聚合)操作,返回结果是RDD[K,V]。
            2)groupByKey:按照key进行分组,直接进行shuffle。
            3)开发指导:在不影响业务逻辑的前提下,优先选用reduceByKey。求和操作不影响业务逻辑,求平均值影响业务逻辑。
        aggregateByKey():按照K处理分区内和分区间逻辑
            aggregateByKey(0)(math.max(_, _), _ + _):取出每个分区相同key对应值的最大值,然后相加
            1)zeroValue(初始值):给每一个分区中的每一种key一个初始值;
            2)seqop(分区内):函数用于在每一个分区中用仞对值还少e1Vaiue;
            3)combOp(分区间):函数用于合并每个分区中的结果。
        foldByKey():分区内和分区间相同的aggregateByKey()
            foldByKey(0)(_+_)等价于.aggregateByKey(0)(_+_,_+_)
            参数zeroValue:是一个初始化值,它可以是任意类型
            参数func:是一个函数,两个输入参数相同
        combineByKey():转换结构后分区内和分区间操作
            1)createCombiner(转换数据的结构): combineByKey() 遍历分区中的所有元素,是一个新的元素,会用createCombiner()函数创建对应的累加器初始值
            2)mergeValue(分区内): 之前已经遇到的键,会使用mergeValue()方法将该键的累加器对应的当前值与这个新的值进行合并
            3)mergeCombiners(分区间): 每个分区独立处理,同一个键有多个累加器。使用mergeCombiners()方法将各个分区的结果进行合并。
        sortByKey():按照K进行排序,默认升序
            在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)的RDD
            按照key的正序(默认顺序)-->sortByKey(true)
            按照key的倒序-->sortByKey(false)
        mapValues():只对V进行操作
        join():连接
            在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))的RDD
        cogroup():类似全连接,在同一个RDD中对key聚合
            在类型为(K,V)和(K,W)的RDD上调用,返回一个(K,(Iterable<V>,Iterable<W>))类型的RDD
            操作两个RDD中的KV元素,每个RDD中相同key中的元素分别聚合成一个集合
Action行动算子
        reduce():聚合
            聚集RDD中的所有元素,先聚合分区内数据,再聚合分区间数据。
        collect():以数组的形式返回数据集
            以数组Array的形式返回数据集的所有元素
            注:所有的数据都会被拉取到Driver端,慎用
            rdd.collect().foreach(println):将RDD内容收集到Driver端打印
        count():返回RDD中元素个数
        first():返回RDD中的第一个元素
        take():返回由RDD前n个元素组成的数组
            take(2):返回RDD中前2个元素
        takeOrdered():返回该RDD排序后前n个元素组成的数组
        aggregate():案例
            aggregate函数将每个分区里面的元素通过分区内逻辑和初始值进行聚合,然后用分区间逻辑和初始值(zeroValue)进行操作。注意:分区间逻辑再次使用初始值和aggregateBykey是有区别的。
        fold():案例
            aggregate的简化操作,即,分区内逻辑和分区间逻辑相同
        countByKey():统计每种key的个数
    save相关算子
        saveAsTextFile(path):保存成Text文件
            将数据集的元素以textfile的形式保存到HDFS文件系统或者其他支持的文件系统,对于每个元素,Spark将会调用toString方法,将它装换为文件中的文本
        saveAsSequenceFile(path):保存成Sequencefile文件
            将数据集中的元素以Hadoop Sequencefile的格式保存到指定的目录下,可以使HDFS或者其他Hadoop支持的文件系统。
        saveAsObjectFile(path):序列化成对象保存到文件
            将RDD中的元素序列化成对象,存储到文件中
    foreach(f):遍历RDD中每一个元素
        遍历RDD中的每一个元素,并依次应用f函数
RDD序列化
    初始化工作是在Driver端进行的,而实际运行程序是在Executor端进行的,这就涉及到了跨进程通信,是需要序列化的
    Driver:算子以外的代码都是在Driver端执行,Executor:算子里面的代码都是在Executor端执行
    extends Serializable
    样例类默认是序列化的
    
    Spark2.0开始支持另外一种Kryo序列化机制。Kryo速度是Serializable的10倍。
    使用Kryo序列化,也要继承Serializable接口
    new SparkConf()
    .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
    // 注册需要使用kryo序列化的自定义类
    .registerKryoClasses(Array(classOf[Searche]))
RDD依赖关系
    RDD的Lineage会记录RDD的元数据信息和转换行为,当该RDD的部分分区数据丢失时,它可以根据这些信息来重新运算和恢复丢失的数据分区。
        查看血缘关系:RDD.toDebugString
        通过dependencies方法,查看RDD的依赖关系
    窄依赖
        每一个父RDD的Partition最多被子RDD的一个Partition使用,窄依赖我们形象的比喻为独生子女。
    宽依赖
        同一个父RDD的Partition被多个子RDD的Partition依赖,会引起Shuffle,总结:宽依赖我们形象的比喻为超生
        具有宽依赖的transformations包括:sort、reduceByKey、groupByKey、join和调用rePartition函数的任何操作。
Stage任务划分
    DAG有向无环图
        由点和线组成的拓扑图形,该图形具有方向,不会闭环
    RDD任务切分中间分为:Application、Job、Stage和Task
        1)Application:初始化一个SparkContext即生成一个Application;
        2)Job:一个Action算子就会生成一个Job;
        3)Stage:Stage等于宽依赖的个数加1;
        4)Task:一个Stage阶段中,最后一个RDD的分区个数就是Task的个数
        注:Application->Job->Stage->Task每一层都是1对n的关系
    stage数量=宽依赖数量+1
    jobtask数量=每个stage最后一个rdd的分区数
    
RDD持久化
    RDD Cache缓存
        通过Cache或者Persist方法计算结果缓存,默认会把数据以序列化的形式缓存在JVM的堆内存中。但是并不是这两个方法被调用时立即缓存,而是触发后面的action时,该RDD将会被缓存在计算节点的内存中,并供后面重用
        Spark会自动对一些Shuffle操作的中间数据做持久化操作(比如:reduceByKey),在实际使用的时候,如果想重用数据,仍然建议调用persist或cache。
    RDD CheckPoint检查点
        检查点:是通过将RDD中间结果写入磁盘。
        如果检查点之后有节点出现问题,可以从检查点开始重做血缘,减少了开销。
        Checkpoint的数据通常是存储在HDFS等容错、高可用的文件系统,存储格式为:二进制的文件
        在Checkpoint的过程中,该RDD的所有依赖于父RDD中的信息将全部被移除。
        检查点触发时间:对RDD进行Checkpoint操作并不会马上被执行,必须执行Action操作才能触发。但是检查点为了数据安全,会从血缘关系的最开始执行一遍。
        1)设置检查点数据存储路径:sc.setCheckpointDir("./checkpoint1")
        2)调用检查点方法:wordToOneRdd.checkpoint()
    缓存和检查点区别
        1)Cache缓存只是将数据保存起来,不切断血缘依赖。Checkpoint检查点切断血缘依赖。
        2)Cache缓存的数据通常存储在磁盘、内存等地方,可靠性低。Checkpoint的数据通常存储在HDFS等容错、高可用的文件系统,可靠性高。
        3)建议对checkpoint()的RDD使用Cache缓存,这样checkpoint的job只需从Cache缓存中读取数据即可,否则需要再从头计算一次RDD。
        4)如果使用完了缓存,可以通过unpersist()方法释放缓存
        注:注意配置访问集群的用户名
键值对RDD数据分区
        Spark目前支持Hash分区、Range分区和用户自定义分区。Hash分区为当前的默认分区。分区器直接决定了RDD中分区的个数、RDD中每条数据经过Shuffle后进入哪个分区和Reduce的个数。
    (1)只有Key-Value类型的RDD才有分区器,非Key-Value类型的RDD分区的值是None
    (2)每个RDD的分区ID范围:0~numPartitions-1,决定这个值是属于那个分区的。
文件类数据读取与保存
    Text文件
        1)数据读取:textFile(String)
        2)数据保存:saveAsTextFile(String)
    Sequence文件
        保存数据为SequenceFile:saveAsSequenceFile("output")
        读取SequenceFile文件:sequenceFile[Int,Int]("output")
    Object对象文件
        保存数据:saveAsObjectFile("output")
        读取数据:objectFile[(Int)]("output")
累加器
    分布式共享只写变量。(Executor和Executor之间不能读数据)
    用来把Executor端变量信息聚合到Driver端。在Driver中定义的变量,在Executor端的每个task都会得到这个变量的一份新的副本,每个task更新这些副本的值后,传回Driver端进行merge。

广播变量
    用来高效分发较大的对象。向所有工作节点发送一个较大的只读值,以供一个或多个Spark操作使用
    使用广播变量步骤
        1)调用SparkContext.broadcast(广播变量)创建出一个广播对象,任何可序列化的类型都可以这么实现。
        2)通过广播变量.value,访问该对象的值。
        3)变量只会被发到各个节点一次,作为只读值处理(修改这个值不会影响到别的节点)。
    声明广播变量:broadcast(list)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值