背景描述:在社交網絡(例如微博)、電子商務(例如京東)、搜索引擎(例如百度)等人們核心關注的內容之一就是我所關注的內容中大家正在最關注什麼或者說當前的熱點是什麼,這在實際企業級應用中是非常有價值的。例如我們關係過去30分鐘大家正在熱搜索什麼,並且每5分鐘更新一次,這就使得熱點內容是動態更新,當然也是更有價值。
我們知道在SparkStreaming中可以設置batchInterval,讓SparkStreaming每隔batchInterval時間提交一次Job,假設batchInterval設置爲5秒,那如果需要對1分鐘內的數據做統計,該如何實現呢?SparkStreaming中提供了window的概念。我們看下圖:
window可以包含多個batchInterval(例如5秒),但是必須爲batchInterval的整數倍例如1分鐘。另外window可以移動,稱之爲滑動時間間隔,它也是batchInterval的整數倍,例如10秒。一般情況滑動時間間隔小於window的時間長度,否則會丟失數據。
SparkStreaming提供瞭如下與window相關的方法:
我們可以使用reduceByKeyAndWindow操作來做具體實現熱詞排序
package com.dt.spark.sparkstreaming import org.apache.spark.SparkConf import org.apache.spark.streaming.{Seconds, StreamingContext} /** * 使用Scala開發集羣運行的Spark來實現在線熱搜索詞 * * @author DT大數據夢工廠 * 新浪微博:http://weibo.com/ilovepains/ * */ object OnlineHottestItems { def main(args: Array[String]){ /** * 第1步:創建Spark的配置對象SparkConf,設置Spark程序的運行時的配置信息, * 例如說通過setMaster來設置程序要鏈接的Spark集羣的Master的URL,如果設置 * 爲local,則代表Spark程序在本地運行,特別適合於機器配置條件非常差(例如 * 只有1G的內存)的初學者 * */ val conf = new SparkConf() //創建SparkConf對象 conf.setAppName("OnlineHottestItems") //設置應用程序的名稱,在程序運行的監控界面可以看到名稱 conf.setMaster("spark://Master:7077") //此時,程序在Spark集羣 /** * 此處設置Batch Interval是在Spark Streaming中生成基本Job的時間單位,窗口和滑動時間間隔 * 一定是該Batch Interval的整數倍 */ val ssc = new StreamingContext(conf, Seconds(5)) val hottestStream = ssc.socketTextStream("Master", 9999) /** * 用戶搜索的格式簡化爲item,time在這裏我們由於要計算出熱點內容,所以只需要提取出item即可 * 提取出的item然後通過map轉換爲(item,1)格式 */ val searchPair = hottestStream.map(_.split(",")(0)).map(item => (item, 1)) val hottestDStream = searchPair.reduceByKeyAndWindow((v1:Int, v2:Int) => v1 + v2, Seconds(60), Seconds(20)) hottestDStream.transform(hottestItemRDD => { val top3 = hottestItemRDD.map(pair => (pair._2, pair._1)).sortByKey(false). map(pair => (pair._2, pair._1)).take(3) ssc.sparkContext.makeRDD(top3) }).print() ssc.start() ssc.awaitTermination() } }
運行程序
root@spark-master:~# /usr/local/spark/spark-1.6.0-bin-hadoop2.6/bin/spark-submit --class com.dt.spark.streaming.OnlineHottestItems --master spark://spark-master:7077 ./spark.jar
打開netcat發送數據
root@spark-master:~# nc -lk 9999 Spark,11111 Spark,2222 hadoop,13143 scala,34343 hadoop,23232 Spark,11111 Spark,2222 hadoop,13143 scala,34343 hadoop,23232 java,34343
打印結果
------------------------------------------- Time: 1462199230000 ms ------------------------------------------- (Spark,4) (hadoop,4) (scala,2)
後續可以在nc中繼續輸入數據,觀察程序打印結果的變化。
上面的代碼每隔20秒都會重新計算之前60秒內的所有數據,如果窗口時間間隔比較長,那麼需要計算的數據量就比較大,非常耗時。
SparkStreaming提供了reduceByKeyAndWindow(func, invFunc,windowLength, slideInterval, [numTasks]) 這個函數,可以實現增量的計算。如下圖:window2 = window1-T1+T4
使用這個函數,必須進行Checkpoint。代碼如下:
ssc.checkpoint("/user/checkpoints/") val ItemCount = ItemPairs.reduceByKeyAndWindow((v1:Int,v2:Int)=> v1+v2,(v1:Int,v2:Int)=> v1-v2,Seconds(60),Seconds(10))