使用Spark rdd 开发spark程序

文章目录

  • 1.常用的rdd
  • rdd的输入和输出,scala版,java版
  • 每个rdd函数的使用场景
  • 特殊rdd的使用选择
    • reduceByKey,groupByKey,的使用选择
    • collect,count的使用选择
  • 总结

1.常用的rdd

函数 说明
map(func) 返回一个新的分布式数据集,由每个原元素经过func函数转换后组成
filter(func) 返回一个新的数据集,由经过func函数后返回值为true的原元素组成
flatMap(func) 类似于map,但是每一个输入元素,会被映射为0到多个输出元素(因此,func函数的返回值是一个Seq,而不是单一元素)
sample(withReplacement, frac, seed) 根据给定的随机种子seed,随机抽样出数量为frac的数据
union(otherDataset) 返回一个新的数据集,由原数据集和参数联合而成
groupByKey([numTasks]) 在一个由(K,V)对组成的数据集上调用,返回一个(K,Seq[V])对的数据集。注意:默认情况下,使用8个并行任务进行分组,你可以传入numTask可选参数,根据数据量设置不同数目的Task
reduceByKey(func, [numTasks]) 在一个(K,V)对的数据集上使用,返回一个(K,V)对的数据集,key相同的值,都被使用指定的reduce函数聚合到一起。和groupbykey类似,任务的个数是可以通过第二个可选参数来配置的。
join(otherDataset, [numTasks]) 在类型为(K,V)和(K,W)类型的数据集上调用,返回一个(K,(V,W))对,每个key中的所有元素都在一起的数据集
reduce(func) 通过函数func聚集数据集中的所有元素。Func函数接受2个参数,返回一个值。这个函数必须是关联性的,确保可以被正确的并发执行
collect() 在Driver的程序中,以数组的形式,返回数据集的所有元素。这通常会在使用filter或者其它操作后,返回一个足够小的数据子集再使用,直接将整个RDD集Collect返回,很可能会让Driver程序OOM
count() 返回数据集的元素个数
take(n) 返回一个数组,由数据集的前n个元素组成。注意,这个操作目前并非在多个节点上,并行执行,而是Driver程序所在机器,单机计算所有的元素(Gateway的内存压力会增大)
first() 返回数据集的第一个元素(类似于take(1))
saveAsTextFile(path) 将数据集的元素,以textfile的形式,保存到本地文件系统,hdfs或者任何其它hadoop支持的文件系统。Spark将会调用每个元素的toString方法,并将它转换为文件中的一行文本
saveAsSequenceFile(path) 将数据集的元素,以sequencefile的格式,保存到指定的目录下,本地系统,hdfs或者任何其它hadoop支持的文件系统。RDD的元素必须由key-value对组成,并都实现了Hadoop的Writable接口,或隐式可以转换为Writable(Spark包括了基本类型的转换,例如Int,Double,String等等)
foreach(func) 在数据集的每一个元素上,运行函数func。这通常用于更新一个累加器变量,或者和外部存储系统做交互

rdd的输入和输出,scala版,java版

scala版本:
https://github.com/zhouyang-bigdata/SparkCommonRdd

java版本:
https://github.com/zhouyang-bigdata/SparkCommonRddJava

每个rdd函数的使用场景

spark 默认提供的rdd多达几十个,其中有与外部连接相关的,比如kafkaRdd,也有专门处理数据的。这里介绍的是专门处理数据的。
spark rdd适合的场景有:

  1. 转换
  2. 过滤
  3. 计数
  4. 排序
  5. 分类
  6. 统计

转换
Map,最有用的转换函数。map() 接收一个函数,把这个函数用于 RDD 中的每个元素,将函数的返回结果作为结果RDD
mapPartition可以倒过来理解,先partition,再把每个partition进行map函数
map,mapToPair:一对一转换。
flatMap,flatMapToPair:一对多转换。

过滤
filter,这通常用于规则校验,条件查询中。条件查询通常有:等于、小于、大于、小于等于、大于等于、模糊匹配,区间等。对于复杂条件,涉及到多个实体对象,需要注意序列化问题。

计数
reduceByKey,reduce,count,accumulator
计数有2种,一种是对值本身累加,一种是对值的数量计数。
reduceByKey接收一个函数,按照相同的key进行reduce操作。
累加器也可以作为计数工具,累加器本身用处是统计程序执行次数,做一些处理,也可以做对值的数量计数。

排序
sortByKey
用于对pairRDD按照key进行排序,第一个参数可以设置true或者false,默认是true。true是升序。
这里有个问题,就是为什么没有sort。也就是对非键值对排序,没有对应的rdd。实际上,可以通过其它rdd去实现。

分类
groupByKey
Cogroup
Reduce
Countbykey
groupByKey会将RDD[key,value] 按照相同的key进行分组,形成RDD[key,Iterable[value]]的形式
cogroup
groupByKey是对单个 RDD 的数据进行分组,还可以使用一个叫作 cogroup() 的函数对多个共享同一个键的 RDD 进行分组 。
分类通常以某个对象为依据。按这个概念,它的用途非常广泛。

统计
统计比较复杂,几乎没有算子单独实现需求。常见的统计有:max,min,avg,sum,趋势。

实际的例子

  1. 条件查询
    查询包含等于、小于、大于、小于等于、大于等于、模糊匹配,区间等条件的数据。
    使用map,filter。
  2. 求最值
    求max,min,avg,sum等数据。
    具体可参见:
    https://github.com/zhouyang-bigdata/SparkRddRealExamples

特殊rdd的使用选择

特殊rdd,对笔者而言,比较特别的rdd跟以下几个方面有联系:

  1. shuffle操作
  2. 在driver上还是在executor上执行
  3. partition的意义
  4. Union,join,aggregate

(1)shuffle操作
我们知道,reducebykey,groupbykey是会发生shuffle操作的。事实上,repartition,join,cogroup,和任何的By或ByKey转换可以导致洗牌。 Shuffle操作,会把转换的中间数据进行分割,然后临时存到磁盘。直到下一次转换,需要从磁盘读取数据。这个操作很低效,而且带来大量内存消耗。为什么会消耗大量内存呢?因为,对于map,filter等操作,从磁盘读取数据也好,还是处理上一步操作的中间数据,数据本身是一个抽象的rdd数据集,数据是以流的形式,小批次的放入内存,在一个时间点,内存消耗并不是很高。而这里的读磁盘数据,是一次性的读取大量数据到内存,内存消耗大。
除此之外,这2个操作,都是宽依赖,同时会产生网络io,io大小与数据量和partition的数量有关。

(2)在driver上还是在executor上执行
这是一个容易犯错的问题。比如foreachRDD,是在driver端执行。foreach,foreachPartition在executor上执行。对于面向外部连接,比如mysql连接,redis连接,hbase连接,我们不想要都在driver端创建,因为这样,每个executor端都从driver端拿数据。这里面有个情况容易混淆,就是:
数据是都在driver端处理还是仅汇总到driver端?
这个区别,直接将Action算子分为2类。

(3)partition的意义
Partition的思路,是把数据分成一块一块的,再使用task并行计算。一般推荐每个真核分2-4partition。Partition与task的关系?
可参见:
https://blog.csdn.net/cafebar123/article/details/79684596

我们知道mappartition在处理外部连接的时候,比map更有效,比如mysql,redis。
使用map与mapPartition,本质区别,是每次载入内存的数据的大小,越大,则函数执行次数越少,综合来说,执行次数越少越好,原因有二:

  1. 函数每执行一次,jvm就需分析一次;次数越少,jvm分析的总时间就越少。

  2. 对于建立外部连接时,比如读取mysql,kafka数据,建立的连接越少越高效。
    但每次载入内存的数据大小,也不能过大。个人建议应不大于每个task分配的内存的1/3。

reduceByKey,groupByKey,的使用选择

collect,count的使用选择

总结

使用Spark rdd 开发spark程序_第1张图片

使用Spark rdd 开发spark程序_第2张图片

你可能感兴趣的:(大数据,spark,scala)