Spark DStream相关操作.docx
- 文档编号:24650748
- 上传时间:2023-05-29
- 格式:DOCX
- 页数:8
- 大小:39.05KB
Spark DStream相关操作.docx
《Spark DStream相关操作.docx》由会员分享,可在线阅读,更多相关《Spark DStream相关操作.docx(8页珍藏版)》请在冰豆网上搜索。
SparkDStream相关操作
SparkDStream相关操作
与RDD类似,DStream也提供了自己的一系列操作方法,这些操作可以分成3类:
普通的转换操作、窗口转换操作和输出操作。
普通的转换操作
普通的转换操作如表1所示
表1普通的转换操作
Suo
描述
map(func)
源DStream的每个元素通过函数func返回一个新的DStream。
flatMap(func)
类似于map操作,不同的是,每个输入元素可以被映射出0或者更多的输出元素
filter(func)
在源DStream上选择func函数的返回值仅为true的元素,最终返回一个新的DStream。
repartition(numPartitions)
通过输入的参数numPartitions的值来改变DStream的分区大小
union(otherStream)
返回一个包含源DStream与其他DStream的元素合并后的新DStream
count()
对源DStream内部所含有的RDD的元素数量进行计数,返回一个内部的RDD只包含一个元素的DStream
reduce(func)
使用函数func(有两个参数并返回一个结果)将源DStream中每个RDD的元素进行聚合操作,返回一个内部所包含的RDD只有一个元素的新DStream
countByValue()
计算DStream中每个RDD内的元素出现的频次并返回新的DStream(
reduceByKey(func,[numTasks])
当一个类型为
可以通过配置numTasks设置不同的并行任务数
join(otherStream,[numTasks])
当被调用类型分别为
cogroup(otherStream,[numTasks])
当被调用的两个DStream分别含有
transform(func)
通过对源DStream的每个RDD应用RDD-to-KDD函数,返回一个新的DStream,这可以用来在DStream中做任意RDD操作
updateStateByKey(func)
返回一个新状态的DStream,其中每个键的新状态是基于前一个状态和其新值通过函数func计算得出的。
这个方法可以被用来维持每个键的任何状态数据
在表1列出的操作中,transform(func)方法和updateStateByKey(fhnc)方法值得再深入地探讨一下。
1.transform(func)方法
transform方法及类似的transformWith(func)方法允许在DStream上应用任意RDD-to-RDD函数,它们可以被应用于未在DStreamAPI中暴露的任何RDD操作中。
例如,每批次的数据流与另一数据集的连接功能不能直接暴露在DStreamAPI中,但可以轻松地使用transform(func)方法来做到这一点,这使得DStream的功能非常强大。
例如,可以通过连接预先计算的垃圾邮件信息的输入数据流,来做实时数据清理的筛选。
事实上,也可以在transform(func)方法中使用机器学习和图形计算的算法。
2.updateStateByKey(func)方法
updateStateByKey(func)方法可以保持任意状态,同时允许不断有新的信息进行更新。
要使用此功能,必须进行以下两个步骤。
1)定义状态:
状态可以是任意的数据类型。
2)定义状态更新函数:
用一个函数指定如何使用先前的状态和从输入流中获取的新值更新状态。
用一个例子来说明,假设要进行文本数据流中单词计数。
在这里,正在运行的计数是状态而且它是一个整数。
更新功能定义如下。
defupdateFunction(newValues:
seq[Int],runningCount:
option[Int]);
Option[Int]={
valnewCount=...//给前序runningCount添加新值,获取新count
Some(newCount)
}
此函数应用于含有键值对的DStream中(例如,在前面的单词计数示例中,在DStream含有
它会针对里面的每个元素(如WordCount中的Word)调用更新函数,其中,newValues是最新的值,runningCount是之前的值。
valrunningCounts=pairs.updateStateByKey[Int](updateFunction._)
窗口转换操作
SparkStreaming还提供了窗口的计算,它允许通过滑动窗口对数据进行转换,窗口转换操作如表2所示
表2窗口转换操作
转换
描述
window(windowLength,slideInterval)
返回一个基于源DStream的窗口批次计算得到新的DStream
countByWindow(windowLength,slideInterval)
返回基于滑动窗口的DStream中的元素的数量
reduceByWindow(func,windowLength,slideInterval)
基于滑动窗口对源DStream中的元素进行聚合操作,得到一个新的DStream
reduceByKeyAndWindow(func,windowLength,slideInterval,[numTasks])
基于滑动窗口对
reduceByKeyAndWindow(func,invFunc,windowLength,slideInterval,[numTasks])
一个更高效的实现版本,先对滑动窗口中新的时间间隔内的数据进行增量聚合,再移去最早的同等时间间隔内的数据统计量。
例如,计算t+4秒这个时刻过去5秒窗口的WordCount时,可以将t+3时刻过去5秒的统计量加上[t+3,t+4]的统计量,再减去[t-2,t-1]的统计量,这种方法可以复用中间3秒的统计量,提高统计的效率
countByValueAndWindow(windowLength,slideInterval,[numTasks])
基于滑动窗口计算源DStream中每个RDD内每个元素出现的频次,并返回DStream[
Reduce任务的数量可以通过一个可选参数进行配置
在SparkStreaming中,数据处理是按批进行的,而数据采集是逐条进行的,因此在SparkStreaming中会先设置好批处理间隔,当超过批处理间隔的时候就会把采集到的数据汇总起来成为一批数据交给系统去处理。
对于窗口操作而言,在其窗口内部会有N个批处理数据,批处理数据的大小由窗口间隔决定,而窗口间隔指的就是窗口的持续时间。
在窗口操作中,只有窗口的长度满足了才会触发批数据的处理。
除了窗口的长度,窗口操作还有另一个重要的参数,即滑动间隔,它指的是经过多长时间窗口滑动一次形成新的窗口。
滑动间隔默认情况下和批次间隔相同,而窗口间隔一般设置得要比它们两个大。
在这里必须注意的一点是,滑动间隔和窗口间隔的大小一定得设置为批处理间隔的整数倍。
如图1所示,批处理间隔是1个时间单位,窗口间隔是3个时间单位,滑动间隔是2个时间单位。
对于初始的窗口(time1~time3),只有窗口间隔满足了才会触发数据的处理。
这里需要注意,有可能初始的窗口没有被流入的数据撑满,但是随着时间的推进/窗口最终会被撑满。
每过2个时间单位,窗口滑动一次,这时会有新的数据流入窗口,窗口则移去最早的2个时间单位的数据,而与最新的2个时间单位的数据进行汇总形成新的窗口(time3~time5)。
图1 DStream的批处理间隔示意
对于窗口操作,批处理间隔、窗口间隔和滑动间隔是非常重要的3个时间概念,是理解窗口操作的关键所在。
输出操作
SparkStreaming允许DStream的数据被输出到外部系统,如数据库或文件系统。
输出操作实际上使transformation操作后的数据可以被外部系统使用,同时输出操作触发所有DStream的transformation操作的实际执行(类似于RDD操作)。
表3列出了目前主要的输出操作。
转换
描述
print()
在Driver中打印出DStream中数据的前10个元素
saveAsTextFiles(prefix,[suffix])
将DStream中的内容以文本的形式保存为文本文件,其中,每次批处理间隔内产生的文件以prefix-TIME_IN_MS[.suffix]的方式命名
saveAsObjectFiles(prefix,[suffix])
将DStream中的内容按对象序列化,并且以SequenceFile的格式保存,其中,每次批处理间隔内产生的文件以prefix—TIME_IN_MS[.suffix]的方式命名
saveAsHadoopFiles(prefix,[suffix])
将DStream中的内容以文本的形式保存为Hadoop文件,其中,每次批处理间隔内产生的文件以prefix-TIME_IN_MS[.suffix]的方式命名
foreachRDD(func)
最基本的输出操作,将func函数应用于DStream中的RDD上,这个操作会输出数据到外部系统,例如,保存RDD到文件或者网络数据库等。
需要注意的是,func函数是在该Streaming应用的Driver进程里执行的
dstream.foreachRDD是一个非常强大的输出操作,它允许将数据输出到外部系统。
但是,如何正确高效地使用这个操作是很重要的,下面来讲解如何避免一些常见的错误。
通常情况下,将数据写入到外部系统需要创建一个连接对象(如TCP连接到远程服务器),并用它来发送数据到远程系统。
出于这个目的,开发者可能在不经意间在SparkDriver端创建了连接对象,并尝试使用它保存RDD中的记录到SparkWorker上,代码如下。
dstream.foreachRDD{rdd=>
valconnection=createNewConnection()//在Driver上执行
rdd.foreach{record=>
connection.send(record)//在Worker上执行
}
}
这是不正确的,这需要连接对象进行序列化并从Driver端发送到Worker上。
连接对象很少在不同机器间进行这种操作,此错误可能表现为序列化错误(连接对不可序列化)、初始化错误(连接对象需要在Worker上进行初始化)等,正确的解决办法是在Worker上创建连接对象。
通常情况下,创建一个连接对象有时间和资源开销。
因此,创建和销毁的每条记录的连接对象都可能会导致不必要的资源开销,并显著降低系统整体的吞吐量。
一个比较好的解决方案是使用rdd.foreachPartition方法创建一个单独的连接对象,然后将该连接对象输出的所有RDD分区中的数据使用到外部系统。
还可以进一步通过在多个RDDs/batch上重用连接对象进行优化。
一个保持连接对象的静态池可以重用在多个批处理的RDD上,从而进一步降低了开销。
需要注意的是,在静态池中的连接应该按需延迟创建,这样可以更有效地把数据发送到外部系统。
另外需要要注意的是,DStream是延迟执行的,就像RDD的操作是由Actions触发一样。
默认情况下,输出操作会按照它们在Streaming应用程序中定义的顺序逐个执行。
持久化
与RDD一样,DStream同样也能通过persist()方法将数据流存放在内存中,默认的持久化方式是MEMORY_ONLY_SER,也就是在内存中存放数据的同时序列化数据的方式,这样做的好处是,遇到需要多次迭代计算的程序时,速度优势十分的明显。
而对于一些基于窗口的操作,如reduceByWindow、reduceByKeyAndWindow,以及基于状态的操作,如updateStateBykey,其默认的持久化策略就是保存在内存中。
对于来自网络的数据源(Kafka、Flume、Sockets等),默认的持久化策略是将数据保存在两台机器上,这也是为了容错性而设计的。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Spark DStream相关操作 DStream 相关 操作