Spark的API操作
1)转换算子
**加粗**的都是常用的,希望可以帮助到大家!!
- Map(fun):对源Rdd的函数操作应用返回一个新的RDD map((word,1)) map(t2=>(t2,1))
- Filter(fun):对源rdd****的元素进行过滤,保留符合条件的元素返回一个新的rdd 列:* filter(t2 => ! t2._1.equals(“b”))
- flatMap**(fun):将rdd****的元素展开为(0-n)的元素,并返回一个新的rdd。**flatMap(line => line.split(" "))
- mapProtitions****(func):都源rdd的每一个分区** 独立应用的函数,返回一个新的****rdd
- mapPartitionsWithIndex(func) : 对源RDD的每一个分区应用函数操作,注意携带分区的索引序号,并返回一个新的RDD
- sample(withreplacement(是否允许重复),fraction(分数,每个数据被抽中的概率),seef(种子,用于底层产生的随机数字)):数据取样采样方法
- union(rdd):将源rdd和新的rdd的数据合并,产生新的rdd
- intersection(rdd):将源rdd和新的rdd的数据做交集,产生新的rdd
- distinct([numpartition]):对源rdd进行元素的去重,是宽依赖
- groupbykey([numpartition]):对源rdd【k,v】进行调用,产生新的rdd[k,v(iteator)](key相同)
- reducebykey(fun,[numpartition]):对一个源rdd《k,v》进行调用,返回一个新的rdd
- aggregatebykey(zeroValue)(seqOp, combOp, [numPartitions]) 注意:首先分区内的计算,其次分区间的计算。
- sortByKey([ascending], [numPartitions]) : 对源RDD(k,v)调用,根据k进行排序返回一个新的RDD
- sortBy:(可以选择建或值,false,1):降序为false 升序为true
- **Join:**两个RDD(K,V)和(K,W)进行连接操作,返回一个新的RDD(K,(V,W))left join、right join
- cogroup(otherDataset, [numPartitions]:共同分组,两个RDD(K,V)和(K,W)进行共同分组,返回一个新的RDD (K, (Iterable, Iterable))
- cartesian(笛卡尔连接):所有的都享用
- pipe(command, [envVars]) : 不是很重要,在RDD的每一个分区执行一个Shell指令或者脚本
- coalesce(numPartitions) : 将源RDD的分区数量减少为numPartitions返回一个新的RDD :注意,如果子类分区量超过父rdd的分区量时,按父rdd的分区量进行计算
- repartition(numPartitions) : 重新分区 stage (TaskSet) --> Task :Partition —> Task:Thread
- repartitionAndSortWithinPartitions(partitioner): 重新分区,并对分区内的数据进行局部排序
2) 行动算子
- reduce:对rdd中的元素进行操作
- collect() : 收集方法,将RDD的所有元素以数组形式返回给Driver端 。mkstring()
- count() : 返回RDD中元素的个数
- first() : 返回RDD中的第一个元素
- take(n) : 返回RDD中的前N个元素, 排行榜
- takeSample(withReplacement, num, [seed]) : 数据采样
- saveAsTextFile(path) : 将RDD中的内容保存到HDFS或者Local File System
- saveAsSequenceFile(path): 将RDD的内容以序列化文件的形式保存在HDFS或者Local FileSystem
- countByKey(): 统计相同key的value数量,返回HashMap
SparkStreaming的API操作
1)转换算子
- 有几个转换算子与SparkApi的功能相同,大家可以对照上面来进行操作和学习.(map,flatmap,repartion,filter)
- union :将两个DStream组合在一起返回一个新的DStream
- count:返回未批Rdd中元素的个数
- reduce :对DStream每一个元素应用函数进行计算 可以在reduce简写 reduce(+)
- countByValue : 对DStream调用 返回DStream相同元素k的出现count (k,count)
- reduceByKey: 根据key应用计算函数
- join :两个DStream进行连接操作 一般都用于(流+批)操作
- cogroup:共同分组,将两个未批RDD进行分组
- transform 对DStream的每一个微批RDD 应用RDD操作,并且返回一个新的DStream 【非常重点】
对于这个是流处理中很重要的一个api操作,在这里给大家举一个实例来梳理:
特点: 将DStream转换为RDD,应用RDD的操作 // 例子:
如有某系统实现抽奖功能, 但是系统黑名单的用户不允许参与抽奖
// 1. 非法的用户 加入系统黑名单【用户名、IP】
// 2. 抽奖请求(正常用户 + 黑名单用户)
// 流(抽奖请求) + 批(黑名单)
val conf=new Sparkconf().appName("reduce").Master("local[*]")
val ssc=new StreamingContext(conf,Seconds(5))//5秒处理一个微批RDD
val ds12 = ssc.socketTextStream("SparkOnStandalone", 9999);
val blacklist = List((1, "zs"), (2, "ww"), (3, "tq"))
val blacklistRDD = ssc.sparkContext.makeRDD(blacklist)
// 流格式:userid method url
ds12
.map(request => {
val arr = request.split(" ")
val userId: Int = arr(0).toInt
val method: String = arr(1)
val url: String = arr(2)
(userId, (method, url))
})
.transform(streamRDD => { // 流 --> 流RDD.leftOuterJoin(批RDD)
streamRDD.leftOuterJoin(blacklistRDD)
})
// 最终仅保留 白名单用户 黑名单用户: (1,((GET,/xxx),Some(zs)))
// 白名单用户: (4,((DELETE,/xxx2),None))
.filter(t2 => t2._2._2.isEmpty) // 是不是为空?
.map(t2 => (t2._1, t2._2._1._1, t2._2._1._2))
.print()
//4. 启动流应用
ssc.start()
//5. 优雅的关闭应用
ssc.awaitTermination()
}
}
- updateStateByKey**(func) :根据key更新状态数据。
- mapWithState:与上面功能相同。都是 更新状态数据
- 相同点:updateStateByKey和mapWithState 用来进行有状态操作相关的转换算子
- 不同点:
- updateStateByKey 将key相同的一组数据,应用状态更新操作;而mapWithState 对每一条数据应用状态更新操作
- updateStateByKey 状态数据全量操作,而mapWithState 状态数据增量操作
- 效率:mapWithState 更高效的状态更新操作,建议使用
2)行动算子
- print :打印Dstream(微批RDD)的前十行数据
- saveAsTextFiles(prefix, [suffix]):以文本文件的形式保存结果 ,参数指定前缀和后缀(它没有指定path,保存到应用的运行目录当中)
- saveAsObjectFiles**(prefix, [suffix]):以序列化的形式保存结果。指定前缀和后缀
- saveAsHadoopFiles**(prefix, [suffix]):以hadoop的文件形式存储,指定前缀和后缀
- foreachRDD**(func) 【重点】:对每一个DStream的微批Rdd应用foreach操作
.foreachRDD(rdd => { // 列举一个将计算结果写到redis中
rdd.foreachPartition(itar => {
val jedisPool = new JedisPool("SparkOnStandalone", 6379)
while (itar.hasNext) {
val element = itar.next()
val jedis = jedisPool.getResource
jedis.set(element._1, element._2.toString)
jedisPool.returnResource(jedis)
}
})
})
流数据的窗口计算API操作
再写API操作前,先给大家说一说窗口的概念,可以更好的理解API操作
窗口:有界有范围的流数据
拆分条件:大小+时间
翻滚窗口:窗口大小固定,数据无重合
滑动(跳跃)窗口:窗口大小固定,数据有重合
这几个图片有助于大家更好的理解 翻滚和滑动
- window**(windowLength, slideInterval):设置窗口的时长
.window(Seconds(60))
countByWindow(windowLength, slideInterval):统计每个窗口中元素的个数
.countByWindow(Seconds(10), Seconds(10))
- reduceByWindow**(func, windowLength, slideInterval):将窗口中的数据进行聚合(计算)操作
.reduceByWindow(_ * _, Seconds(10), Seconds(10))
- reduceByKeyAndWindow**(func, windowLength, slideInterval, [numTasks]):将窗口中的函数按照key,进行reduce函数计算
.reduceByKeyAndWindow((v1: Int, v2: Int) => v1 + v2, Seconds(10), Seconds(10))
- reduceByKeyAndWindow**(func, invFunc, windowLength, slideInterval, [numTasks]):更高效的reduce计算
.reduceByKeyAndWindow((v1: Int, v2: Int) => v1 + v2, (v1: Int, v2: Int) => v1 - v2, Seconds(5), Seconds(2))
- countByValueAndWindow**(windowLength, slideInterval, [numTasks]):对相同key的值,进行value的累加
.countByValueAndWindow(Seconds(5),Seconds(5))
v1 + v2, (v1: Int, v2: Int) => v1 - v2, Seconds(5), Seconds(2))
- countByValueAndWindow**(windowLength, slideInterval, [numTasks]):对相同key的值,进行value的累加
.countByValueAndWindow(Seconds(5),Seconds(5))