一、DStream轉換操作
1、DStream無狀態轉換操作
每次統計,和之前批次無關,不會進行累計
-
map(func) :對源DStream的每個元素,採用func函數進行轉換,得到一個新的Dstream
-
flatMap(func): 與map相似,但是每個輸入項可用被映射爲0個或者多個輸出項
-
filter(func): 返回一個新的DStream,僅包含源DStream中滿足函數func的項
-
repartition(numPartitions): 通過創建更多或者更少的分區改變DStream的並行程度
-
reduce(func):利用函數func聚集源DStream中每個RDD的元素,返回一個包含單元素RDDs的新DStream
-
count():統計源DStream中每個RDD的元素數量
-
union(otherStream): 返回一個新的DStream,包含源DStream和其他DStream的元素
-
countByValue():應用於元素類型爲(K,V)的DStream上,返回一個(K,V)鍵值對類型的新DStream,每個鍵的值是在原DStream的每個RDD中的出現次數
-
reduceByKey(func, [numTasks]):當在一個由(K,V)鍵值對組成的DStream上執行該操作時,返回一個新的由(K,V)鍵值對組成的DStream,每一個key的值均由給定的recuce函數(func)聚集起來
-
join(otherStream, [numTasks]):當應用於兩個DStream(一個包含(K,V)鍵值對,一個包含(K,W)鍵值對),返回一個包含(K, (V, W))鍵值對的新Dstream
-
cogroup(otherStream, [numTasks]):當應用於兩個DStream(一個包含(K,V)鍵值對,一個包含(K,W)鍵值對),返回一個包含(K, Seq[V], Seq[W])的元組
-
transform(func):通過對源DStream的每個RDD應用RDD-to-RDD函數,創建一個新的DStream。支持在新的DStream中做任何RDD操作
2、DStream有狀態轉換操作
A、滑動窗口轉換操作
-
事先設定一個滑動窗口的長度(也就是窗口的持續時間)
-
設定滑動窗口的時間間隔(每隔多長時間執行一次計算),讓窗口按照指定時間間隔在源DStream上滑動
-
每次窗口停放的位置上,都會有一部分Dstream(或者一部分RDD)被框入窗口內,形成一個小段的Dstream
-
可以啓動對這個小段DStream的計算
(1)一些窗口轉換操作的含義
-
window(windowLength, slideInterval) 基於源DStream產生的窗口化的批數據,計算得到一個新的Dstream
-
countByWindow(windowLength, slideInterval) 返回流中元素的一個滑動窗口數
-
reduceByWindow(func, windowLength, slideInterval) 返回一個單元素流。利用函數func聚集滑動時間間隔的流的元素創建這個單元素流。函數func必須滿足結合律,從而可以支持並行計算
-
reduceByKeyAndWindow(func, windowLength, slideInterval, [numTasks]) 應用到一個(K,V)鍵值對組成的DStream上時,會返回一個由(K,V)鍵值對組成的新的DStream。每一個key的值均由給定的reduce函數(func函數)進行聚合計算。注意:在默認情況下,這個算子利用了Spark默認的併發任務數去分組。可以通過numTasks參數的設置來指定不同的任務數
-
reduceByKeyAndWindow(func, invFunc, windowLength, slideInterval, [numTasks]) 更加高效的reduceByKeyAndWindow,每個窗口的reduce值,是基於先前窗口的reduce值進行增量計算得到的;它會對進入滑動窗口的新數據進行reduce操作,並對離開窗口的老數據進行“逆向reduce”操作。但是,只能用於“可逆reduce函數”,即那些reduce函數都有一個對應的“逆向reduce函數”(以InvFunc參數傳入)
-
countByValueAndWindow(windowLength, slideInterval, [numTasks]) 當應用到一個(K,V)鍵值對組成的DStream上,返回一個由(K,V)鍵值對組成的新的DStream。每個key的值都是它們在滑動窗口中出現的頻率
B、updateStateByKey操作
需要在跨批次之間維護狀態時,就必須使用updateStateByKey操作
詞頻統計實例:
對於有狀態轉換操作而言,本批次的詞頻統計,會在之前批次的詞頻統計結果的基礎上進行不斷累加,所以,最終統計得到的詞頻,是所有批次的單詞的總的詞頻統計結果
import org.apache.spark._
import org.apache.spark.streaming._
import org.apache.spark.storage.StorageLevel
object NetworkWordCountStateful {
def main(args: Array[String]) {
//定義狀態更新函數
val updateFunc = (values: Seq[Int], state: Option[Int]) => {
val currentCount = values.foldLeft(0)(_ + _)
val previousCount = state.getOrElse(0)
Some(currentCount + previousCount)
}
StreamingExamples.setStreamingLogLevels() //設置log4j日誌級別
val conf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCountStateful")
val sc = new StreamingContext(conf, Seconds(5))
//設置檢查點,檢查點具有容錯機制
sc.checkpoint("file:///usr/local/spark/mycode/streaming/stateful/")
val lines = sc.socketTextStream("localhost", 9999)
val words = lines.flatMap(_.split(" "))
val wordDstream = words.map(x => (x, 1))
val stateDstream = wordDstream.updateStateByKey[Int](updateFunc)
stateDstream.print()
sc.start()
sc.awaitTermination()
}
}
二、輸出操作
在Spark應用中,外部系統經常需要使用到Spark DStream處理後的數據,因此,需要採用輸出操作把DStream的數據輸出到數據庫或者文件系統中
1 、把DStream輸出到文本文件中
package org.apache.spark.examples.streaming
import org.apache.spark._
import org.apache.spark.streaming._
import org.apache.spark.storage.StorageLevel
object NetworkWordCountStateful {
def main(args: Array[String]) {
//定義狀態更新函數
val updateFunc = (values: Seq[Int], state: Option[Int]) => {
val currentCount = values.foldLeft(0)(_ + _)
val previousCount = state.getOrElse(0)
Some(currentCount + previousCount)
}
StreamingExamples.setStreamingLogLevels() //設置log4j日誌級別
val conf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCountStateful")
val sc = new StreamingContext(conf, Seconds(5))
//設置檢查點,檢查點具有容錯機制
sc.checkpoint("file:///usr/local/spark/mycode/streaming/dstreamoutput/")
val lines = sc.socketTextStream("localhost", 9999)
val words = lines.flatMap(_.split(" "))
val wordDstream = words.map(x => (x, 1))
val stateDstream = wordDstream.updateStateByKey[Int](updateFunc)
stateDstream.print()
//下面是新增的語句,把DStream保存到文本文件中
stateDstream.saveAsTextFiles("file:///usr/local/spark/mycode/streaming/dstreamoutput/output.txt")
sc.start()
sc.awaitTermination()
}
}
2、把DStream寫入到MySQL數據庫中
package org.apache.spark.examples.streaming
import java.sql.{PreparedStatement, Connection, DriverManager}
import java.util.concurrent.atomic.AtomicInteger
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.StreamingContext._
import org.apache.spark.storage.StorageLevel
object NetworkWordCountStateful {
def main(args: Array[String]) {
//定義狀態更新函數
val updateFunc = (values: Seq[Int], state: Option[Int]) => {
val currentCount = values.foldLeft(0)(_ + _)
val previousCount = state.getOrElse(0)
Some(currentCount + previousCount)
}
StreamingExamples.setStreamingLogLevels() //設置log4j日誌級別
val conf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCountStateful")
val sc = new StreamingContext(conf, Seconds(5))
//設置檢查點,檢查點具有容錯機制
sc.checkpoint("file:///usr/local/spark/mycode/streaming/dstreamoutput/")
val lines = sc.socketTextStream("localhost", 9999)
val words = lines.flatMap(_.split(" "))
val wordDstream = words.map(x => (x, 1))
val stateDstream = wordDstream.updateStateByKey[Int](updateFunc)
stateDstream.print()
//下面是新增的語句,把DStream保存到MySQL數據庫中
stateDstream.foreachRDD(rdd => {
//內部函數
def func(records: Iterator[(String,Int)]) {
var conn: Connection = null
var stmt: PreparedStatement = null
try {
val url = "jdbc:mysql://localhost:3306/spark"
val user = "root"
val password = "hadoop" //數據庫密碼是hadoop
conn = DriverManager.getConnection(url, user, password)
records.foreach(p => {
val sql = "insert into wordcount(word,count) values (?,?)"
stmt = conn.prepareStatement(sql);
stmt.setString(1, p._1.trim)
stmt.setInt(2,p._2.toInt)
stmt.executeUpdate()
})
} catch {
case e: Exception => e.printStackTrace()
} finally {
if (stmt != null) {
stmt.close()
}
if (conn != null) {
conn.close()
}
}
}
val repartitionedRDD = rdd.repartition(3)
repartitionedRDD.foreachPartition(func)
})
sc.start()
sc.awaitTermination()
}
}