0. 零碎概念

(1)

这个有点疑惑,有可能是错误的。

(2)

此处就算地址写错了也不会报错,因为此操作只是读取数据的操作(元数据),表示从此地址读取数据但并没有进行读取数据的操作

(3)分区(有时间看HaDoopRDD这个方法的源码,用来计算分区数量的)

物理切片:实际将数据切分开,即以前的将数据分块(每个数据块的存储地址不一样),hdfs中每个分块的大小为128m

逻辑切片:指的是读取数据的时候,将一个数据逻辑上分成多块(这个数据在地址上并没有分开),即以偏移量的形式划分(各个Task从某个数据的不同位置读取这个数据)

分区数与最小分区数有关,如果最小分区数为1 ,输入切片小于128m,就不在进行逻辑切分多个输入切片了。如果最小分区数为2,有两个文件,一个文件比较大,一个文件比较小,大的文件会被逻辑划分为两个输入切片,即大的文件对应两个分区,小的文件对应一个分区

   一般来说,一个文件对应于一个分区数,但是若两个文件的大小相差很大,则一个文件会有2个分区,即将这个大的文件进行了逻辑切片,如下

文件夹下有2个文件:1.txt,words.txt(words.txt比1.txt大很多)

在IDEA中执行wc任务后,日志文件如下,可见words.txt被逻辑切片成了两个分区

如果自己指定的分区数小于输入的切片数,则分区数会默认使用切片数作为分区数

注意:文件进行逻辑切片的条件:

  (一个文件的字节数据 / (目录下文件总的字节数 / 最小分区的数量)) > 1.1 就划分多个输入切片

最小分区数一般为2,但当自己设置并行度为1时,则最小分区数为1,原因如下:

 补充: 为什么最小分区数一般为2呢?

  spark本身就是个分布式的运算框架,其进行分布式运算的核心即为分布式数据集(RDD),rdd分区数有多少意味着task会有多少,并并行度有多少。若是rdd的分区数为1,则不是分布式运算了,就没意义了

例:

wc1目录中有3个文件,大小如下

代码(用来测试分区数)

object WordCount {
def main(args: Array[String]): Unit = {
// val conf: SparkConf = new SparkConf().setAppName("WordCount")
//往HDFS中写入数据,将程序的所属用户设置成更HDFS一样的用户
System.setProperty("HADOOP_USER_NAME", "root")
//Spark程序local模型运行,local[*]是本地运行,并开启多个线程
val conf: SparkConf = new SparkConf()
.setAppName("WordCount")
.setMaster("local[*]") //设置为local模式执行
// 1 创建SparkContext,使用SparkContext来创建RDD
val sc: SparkContext = new SparkContext(conf)
// spark写Spark程序,就是对神奇的大集合【RDD】编程,调用它高度封装的API
// 2 使用SparkContext创建RDD
val lines: RDD[String] = sc.textFile("hdfs://feng05:9000/wc1", 1)
println(lines.partitions.length)
lines.saveAsTextFile("E:/javafile/wc/out4")
// 释放资源
sc.stop()
}
}

运行结果:3个分区

查看日志文件,如下,发现words.txt没有进行逻辑切片(符合上面逻辑切片发生的条件)

上面自己设定的并行度为1,导致最小分区为1,下面不设置并行度(其他代码同上),即最小分区会变成2,这个时候,按照上面逻辑切分的条件,words.txt会被逻辑切分为两个切片,即最终会得到4个分区,事实也是如此,如下日志文件

如果最小分区数为1 ,输入切片小于128m,就不在进行逻辑切分多个输入切片了,若大于128m,则会被逻辑切分成2个切片(几乎平均切分)

总结:

  从hdfs中读取数据创建rdd,其并没有立即读取数据,而是记录以后要从hdfs中某个地址读取数据(读取数据的操作由其调度的task来执行),分区的数量有输入切片来决定。输入切片并不是看到的文件数量以及分块数,而是在读取数据的时候,尽量让每个task读取的数据大小均匀,所以相对大的文件会进行逻辑切片,即输入切片的数目就会增大

  • 并行化的方式创建rdd
 // 使用parallelize
val rdd1 =sc.parallelize(List(1,2,3,4,5,6,7))

此处的并行度与一开始设置的executor-cores有关,若设置为3,则会有3个分区,则会有3个Task

分区和分区器的区别

  分区是rdd用来决定spark中task的并行度的,而分区器则是决定上游的数据到下游哪个地方的(类似MR程序中,maptask处理完的数据会被分到下游的哪个reduceTask中)

(3) RDD中的collect

  collect相当于将executor计算好的数据收集起来,放置于driver端,以下是具体的

1. RDD的使用

1.0  什么是RDD

  RDD(Resilient Distributed Dataset)是一个抽象数据集,RDD中不保存要计算的数据集,保存的是元数据,即数据的描述信息和运算逻辑,比如数据要从哪里去读取,怎么运算等。RDD可以理解为一个代理,你对RDD进行操作,相当于在Driver端先是记录下计算的描述信息,然后生成Task,将Task调度到Executor端才执行真正的计算逻辑

1.1 RDD的特点

  •  有一些连续的分区

  分区编号从0开始,分区数量决定了对应阶段Task的并行度

  • 有一个函数作用在每个输入切片上

  每一个分区都会生成一个Task,对该分区的数据进行计算,这个函数就是具体的计算逻辑

  •  RDD和RDD之间存在一些依赖关系

  RDD调用Transformation后会生成一个新的RDD,子RDD会记录父RDD的依赖关系,包括宽依赖(有shuffle)和窄依赖(没有shuffle)

  • (可选的)K-V的RDD在shuffle会有分区器,默认使用HashPartioner
  •  (可选的)如果从HDFS中读取数据,会有一个最优位置:  

  spark在调度任务之前会读取NameNode的元数据信息,获取数据的位置,移动计算而不是移动数据,这样可以提高计算效率

 1.2 创建RDD的方式

1.2.1 读取外部文件的方式

(1)读取HDFS中的文件创建RDD

private def makeRDDFromHDFS = {
val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
val sc = new SparkContext(conf)
val rdd: RDD[String] = sc.textFile("hdfs://doit01:9000/word.txt")
sc.stop()
}

这里要注意分区问题,见0处的分区

(2)读取本地数据创建RDD

private def makeRDDFromDisk = {
val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
val sc = new SparkContext(conf)
// 返回的是处理整个文件数据的RDD
val rdd: RDD[String] = sc.textFile("d://word.txt")
rdd.foreach(println)
sc.stop()
}

1.2.2 集合转换(一般使用parallelize方法)

private def arrayToRDD = {
val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
val sc = new SparkContext(conf)
val arr = Array("java", "vue", "js", "hive", "scala", "hbase")
val rdd: RDD[String] = sc.makeRDD(arr) // 底层调用的就是parallelize
// 参数一数据集 参数二 将数据集划分成N区,有利于分布式运算(将不同区的数据交给不同的worker去处理)
val rdd2: RDD[String] = sc.parallelize(arr, 3)
rdd.foreach(println)
sc.stop()
}

注意:

(1)makeEDD或者是parallelize方法接收的参数只能是seq序列(Array,List等,set和map不属于),map和set想转成RDD需要先将之转换成Arrat或者是List

(2)集合转成RDD时,如果本地运行(local[n]),并且makeEDD或者是parallelize方法没有指定分区数时,则得到的RDD分区数为n

1.2.3  RDD调用转换算子获取RDD

1.3  RDD的算子分类

  • Transformation:即转换算子,调用转换算子会生成一个新的RDD,R=Transfoemation是Lazzy的,不会触发job的执行
  • Action:行动算子,调用行动算子会触发job执行,本质上调用了sc.runJob方法,该方法从最后一个RDD,根据其依赖关系,从后往前,划分Stage,生成TaskSet  

1.3.1 RDD常用的Transformation算子

  • map算子,功能是做映射

 将原数据的每个元素传给函数func进行格式化,返回一个新的分布式数据集。源码如下

测试(spark-shell中测试)

  •  flatMap算子,先map再压平,spark中没有flatten方法

测试

(1)

此处若将flatMap换成map则会有如下结果

flat相当于压平操作,外部的Array可比成一个大的气球,里面的各个Array相当于里面的小气球,而flat的操作就是将这些小气球压破,使所有元素都放在外部的气球(Array)中

(2)测试的数据位集合中包含集合(使用了两次flatMap)

此处若将flatMap换成map,则运行的结果为

  • filter算子 ,功能为过滤数据

  •  mapPartitions

  将数据以分区的形式返回map操作,一个分区对应一个迭代器,该方法和map方法类似,只不过该方法的参数由RDD中的每一个元素变成了RDD中每一个分区的迭代器,如果在映射的过程中需要频繁创建额外的对象,使用mapPartions要比map高效的多

  使用map的话,若是要从数据库中拿数据,则每拿一条数据就要建立一次数据库的连接,比较耗费性能,但mapPartitions则是一个分区建立一次连接,这一个连接可以处理这个分区中的数据

  • mapPartitionsWithIndex

  类似于mapPartitions,不过函数要输入两个参数,第一个参数为分区的索引,第二个是对应分区的迭代器。函数返回的是一个经过该函数转换的迭代器

  • sortBy算子,用来排序

  此处若是将函数x=>x改为x=>x+“”,表示的是排序以字符串的形式排

  • sortByKey算子,按照key排序

  • groupBy算子,分组,既可以按照key也可以按照值分组

将_1换成_2就是按值排序了

  •  groupByKey 按照key进行分组

  只能按照key排序,不需要参数

   hello和flink的hashcode值一样,所以在一个分区中,但不在一个分组中,一个分区可以有多个分组

  • reduceByKey

  reduceByKey就是对元素为KV对的RDD中Key相同的元素进行binary_function的reduce操作(见action算子部分),因此,Key相同的多个元素的值被reduce为一个值,然后RDD中的Key组成一个新的KV对

groupByKey结合mapValues也能达到此聚合的目的,如下

那么,groupByKey和reduceByKey有什么区别呢?

  GroupByKey是直接将数据分组到下游,没有对数据进行处理,加大了shuffle的网络传输,但ReduceByKey则不一样,reduceByKey先是局部聚合再全局聚合,可以减少shuffle网络传输,提高聚合效率,两者的逻辑图如下

  • distinct算子,去重

  • union,intersection,subtract  

  •  join,相当于SQL中的内关联

  •  leftOuterJoin,相当于SQL中的左外关联

  •  rightOuterJoin,相当于SQL中的右外关联

  •  fullOuterJoin,相当于SQL中的全关联

  •  cartesian算子,笛卡尔积

  •  cogroup算子(用的比较多),协分组,有点跟fullOuterJoin类似,但是没有关联上的返回CompactBuffer()

源码如下

  Other,this,that,找个时间看下

  • aggregateByKey

  按照key进行聚合,跟reduceByKey类似,可以输入两个函数,第一个函数局部聚合,第二个函数全局聚合。初始值自在局部聚合时使用,全局聚合不使用。源码如下

例()

此处有两个分区,第一个分区中分为两个组cat部分和mouse部分,所以第一个分区的cat值为100,mouse也为100,同理第二个分区,所以得到如图所示的结果

  • combineByKey

  需要输入三个参数,第一个参数为分组后value的第一个元素,第二个参数为局部聚合函数,第三个参数为全局聚合函数

  reduceByKey、foldByKey、aggregateByKey、combineByKey底层调用的都是combineByKeyWithClassTag

 例1

 

x=>x:取出分区后各个组中value的第一个元素;(a: Int, b: Int) => a + b :将各个组的值相加,即局部聚合;(m: Int, n: Int) => m + n:此处m表示第一个分区中的值,n为第二个分区中的值,将各个分区中key相同的值相加,即全局聚合

例2

解法如下:

 x=>List(x):将分组后各组中value的第一个元素放入一个List;(a:List[String],b:String) => a:+b:将分组后各组中value的其他元素也加到各自的List中;(m:List[String],n:List[String]) => m ++ n):全局聚合

知识点补充

1.3.2 RDD常用的Action算子

  • reduce(binary_function)

  reduce将RDD中元素前两个传给输入函数,产生一个新的return值,新产生的return值与RDD中下一个元素(第三个元素)组成两个元素,再被传给输入函数,直到最后只有一个值为止

  与reduce对应的算子是fold,与reduce不同的是reduce可以给一个初始值,此处的初始值在局部聚合和全局聚合都会使用(foldByKey只是在聚不聚合时使用了初始值)

  •  collect,将数据以数组形式手机回收Driver端,数据按照分区编号有序返回

  

  •  count,返回rdd元素的数量

  •  top 将RDD中数据按照降序(默认降序)或者指定的排序规则,返回前n个数据

  •  take,返回一个由数据集的前n个元素组成的数组

  •  first,返回数据集中的第一个元素

  •  takeOrdered和top类似,默认升序返回

  •  saveAsTextFile以文本的形式保存到文件系统中
val rdd1 = sc.parallelize(List(3,2,4,1,5), 2)  //2个分区
rdd1.saveAsTextFile("hdfs://feng05:9000/haha")

结果查看

  • aggregate, 传入两个函数,第一个函数在分区内聚合,第二个全局聚合,可以传初始值,并且初始值在聚不聚he和全局聚合都会被使用

 

  • foreach  将数据一条一条的取出来进行处理,函数没有返回

task是在excutor中执行,此处的spark-shell为Driver端,数据并没有被收集到Driver端,前面能返回数据都是因为executor的数据被收集到Driver端,所以才能被显示,要想看到结果可以去executor的输出日志中看,如下

  •  foreachPartition, 和foreach类似,只不过是以分区为单位,一个分区对应一个迭代器,应用外部传的函数,函数没有返回值,通常使用该方法将数据写入到外部存储系统中,一个分区获取一个连接,效果更高

若直接打印迭代器,并不会将数据迭代出来,打印的只是迭代器的引用地址,所以使用foreach(迭代器中的foreach)将之遍历出来

 2.Spark中的一些重要概念

 2.1 Application

 使用SparkSubmit提交的计算应用,一个Application中可以触发Action,触发一次Action产生一个Job,一个Application中可以有一到多个Job

  Application是Driver在构建SparkContent的上下文的时候创建的, 就想申报员,现在要构建一个能完成任务的集群,需要申报的是这次需要多少个Executor,每个executor需要多少内存,以及所有executor可用的cpu数

 2.2 Job

  Driver向Executor提交的作业,触发一次Acition形成一个完整的DAG,一个DAG对应一个Job,一个Job中有多个Stage,一个Stage中有多个Task

2.3 DAG

  概念:有向无环图(即RDD有方向没有形成闭环,如下图),是对多个RDD转换过程和依赖关系的描述,触发Action就会形成一个完整的DAG,一个DAG对应一个Job

2.4 Stage

  概念:任务执行阶段,Stage执行是有先后顺序的,先执行前的,在执行后面的,一个Stage对应一个TaskSet,一个TaskSet中的Task的数量取决于Stage中最后一个RDD分区的数量

2.5 Task

  概念:Spark中任务最小的执行单元,Task分类两种,即ShuffleMapTask和ResultTask

Task其实就是类的实例,有属性(从哪里读取数据),有方法(如何计算),Task的数量决定决定并行度,同时也要考虑可用的cores

 2.6 TaskSet

  保存同一种计算逻辑多个Task的集合,一个TaskSet中的Task计算逻辑都一样,计算的数据不一样

大数据学习day19-----spark02-------0 零碎知识点(分区,分区和分区器的区别) 1. RDD的使用(RDD的概念,特点,创建rdd的方式以及常见rdd的算子) 2.Spark中的一些重要概念的更多相关文章

  1. 大数据学习(一) | 初识 Hadoop

    作者: seriouszyx 首发地址:https://seriouszyx.top/ 代码均可在 Github 上找到(求Star) 最近想要了解一些前沿技术,不能一门心思眼中只有 web,因为我目 ...

  2. 大数据学习之 LINUX

    ##大数据学习 古斌6.6 01. linux系统的搭建: 选用 Contos 6.5 x64位系统 (CentOS-6.5-x86_64-minimal.iso) 我选择的为迷你版 模板机: bla ...

  3. 大数据学习day31------spark11-------1. Redis的安装和启动,2 redis客户端 3.Redis的数据类型 4. kafka(安装和常用命令)5.kafka java客户端

    1. Redis Redis是目前一个非常优秀的key-value存储系统(内存的NoSQL数据库).和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list ...

  4. 大数据学习day29-----spark09-------1. 练习: 统计店铺按月份的销售额和累计到该月的总销售额(SQL, DSL,RDD) 2. 分组topN的实现(row_number(), rank(), dense_rank()方法的区别)3. spark自定义函数-UDF

    1. 练习 数据: (1)需求1:统计有过连续3天以上销售的店铺有哪些,并且计算出连续三天以上的销售额 第一步:将每天的金额求和(同一天可能会有多个订单) SELECT sid,dt,SUM(mone ...

  5. 大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 图文详解

    引言 在之前的大数据学习系列中,搭建了Hadoop+Spark+HBase+Hive 环境以及一些测试.其实要说的话,我开始学习大数据的时候,搭建的就是集群,并不是单机模式和伪分布式.至于为什么先写单 ...

  6. 大数据学习系列之九---- Hive整合Spark和HBase以及相关测试

    前言 在之前的大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 中介绍了集群的环境搭建,但是在使用hive进行数据查询的时候会非常的慢,因为h ...

  7. 大数据学习之Linux进阶02

    大数据学习之Linux进阶 1-> 配置IP 1)修改配置文件 vi /sysconfig/network-scripts/ifcfg-eno16777736 2)注释掉dhcp #BOOTPR ...

  8. 大数据学习系列之—HBASE

    hadoop生态系统 zookeeper负责协调 hbase必须依赖zookeeper flume 日志工具 sqoop 负责 hdfs dbms 数据转换 数据到关系型数据库转换 大数据学习群119 ...

  9. 大数据学习之Hadoop快速入门

    1.Hadoop生态概况 Hadoop是一个由Apache基金会所开发的分布式系统集成架构,用户可以在不了解分布式底层细节情况下,开发分布式程序,充分利用集群的威力来进行高速运算与存储,具有可靠.高效 ...

随机推荐

  1. Python import commands ImportError: No module named 'commands'

    ImportError: No module named 'commands' 在Python3中执行shell脚本,想要获取其执行状态和标准输出.错误输出 的数据,遇到这个错误,原因是command ...

  2. 让Visual Studio x64 支持 __asm内联汇编

    目录 让Visual Studio x64 支持 __asm内联汇编 Intel Parallel Studio XE 2016安装 设置Interl C++ Compiler 使VS x64支持内联 ...

  3. Code Runner,率先支持刚发布的 Visual Studio 2022!

    Visual Studio 被不少网友成为"宇宙第一IDE".但是,我写✍ PHP.Java 和 C#,也都是用的 VS Code. 我所在的组,是 Visual Studio C ...

  4. 《手把手教你》系列技巧篇(四十一)-java+ selenium自动化测试 - 处理iframe -上篇(详解教程)

    1.简介 原估计宏哥这里就不对iframe这个知识点做介绍和讲解了,因为前边的窗口切换就为这种网页处理提供了思路,另一个原因就是虽然iframe很强大,但是现在很少有网站用它了.但是还是有小伙伴或者童 ...

  5. mysql 禁止外键检查

    SET FOREIGN_KEY_CHECKS=0; SET FOREIGN_KEY_CHECKS=1; from: https://stackoverflow.com/a/15501754/80250 ...

  6. 第二课 Dubbo设计的架构设计

    总体架构 Dubbo的总体架构,如图所示: Dubbo框架设计一共划分了10个层,而最上面的Service层是留给实际想要使用Dubbo开发分布式服务的开发者实现业务逻辑的接口层.图中左边淡蓝背景的为 ...

  7. 15-Transfer Learning

    介绍 迁移学习指的就是,假设你手上有一些跟你现在要进行的task没有直接相关的data,那你能不能用这些没有直接相关的data来帮助我们做一些什么事情.比如说:你现在做的是猫跟狗的classifer, ...

  8. 14-1-Unsupervised Learning ---dimension reduction

    无监督学习(Unsupervised Learning)可以分为两种: 化繁为简 聚类(Clustering) 降维(Dimension Reduction) 无中生有(Generation) 所谓的 ...

  9. SQL中单引号和双引号

    比如说: String sql = "select * from clients where logname='" + name + "'and password='&q ...

  10. 【Tool】Node.js 安装

    Node.js 安装 2019-07-29  14:56:14  by冲冲 1. 说明 电脑使用node.js存在两种方式: ① 第一种,下载(.exe)到本地电脑,不需要安装,下载后点击 node. ...