黑名單實時過濾
一、實驗介紹
1.1 實驗內容
本節課主要講解 Spark 的 RDD 操作,讓您對 Spark 算子的特性快速瞭解。通過演示案例實時黑名單過濾,讓您切身體會到 RDD 的強大功能,然後學以致用。
1.2 先學課程
1.3 實驗知識點
- nc
- SparkStreaming
- Spark RDD
1.4 實驗環境
spark-2.1.0-bin-hadoop2.6
Xfce 終端
1.5 適合人羣
本課程屬於中級難度級別,適合具有 Spark 基礎的用戶,如果對 Scala 熟悉 ,能夠更好的上手本課程。
二、彈性分佈式數據集(RDD)
提到 Spark Transformation,不得不說 Spark RDD,那麼 RDD 是什麼?
彈性分佈式數據集(RDD)是 Spark 框架中的核心概念。它是由數據組成的不可變分佈式集合,其主要進行兩個操作:transformation 和 action。Spark 將數據存儲在不同分區上的 RDD 之中,RDD 可以幫助重新安排計算並優化數據處理過程,此外,它還具有容錯性,因爲 RDD 知道如何重新創建和重新計算數據集。Transformation 是類似在 RDD上 做 filter()、map()或 union() 以生成另一個 RDD 的操作,而 action 則是 count()、first()、take(n)、collect() 等觸發一個計算操作。Transformations 一般都是 lazy 的,直到 action 執行後纔會被執行。Spark Master/Driver 會保存 RDD 上的 Transformations。這樣一來,如果某個 RDD 丟失,它可以快速和便捷地轉換到集羣中存活的主機上。這也就是 RDD 的彈性所在。
RDD 支持兩種類型的操作:
變換(Transformation)
變換的返回值是一個新的 RDD 集合,而不是單個值。調用一個變換方法,不會有任何求值計算,它只獲取一個 RDD 作爲參數,然後返回一個新的 RDD。變換函數包括:map,filter,flatMap,groupByKey,reduceByKey,aggregateByKey,pipe 和 coalesce。行動(Action)
行動操作計算並返回一個新的值。當在一個 RDD 對象上調用行動函數時,會在這一時刻計算全部的數據處理查詢並返回結果值。行動操作包括:reduce,collect,count,first,take,countByKey 以及 foreach。
2.1 transformation 操作
map(func):
對調用 map 的 RDD 數據集中的每個 element 都使用 func,然後返回一個新的 RDD,這個返回的數據集是分佈式的數據集。filter(func):
對調用 filter 的 RDD 數據集中的每個元素都使用 func,然後返回一個包含使 func 爲 true 的元素構成的 RDD。flatMap(func):
和 map 差不多,但是 flatMap 生成的是多個結果。mapPartitions(func):
和 map 很像,但是 map 是每個 element,而 mapPartitions 是每個 partition。mapPartitionsWithSplit(func):
和 mapPartitions 很像,但是 func 作用的是其中一個 split 上,所以 func 中應該有 index。sample(withReplacement,faction,seed):
抽樣。union(otherDataset):
返回一個新的 dataset,包含源 dataset 和給定 dataset 的元素的集合。distinct([numTasks]):
返回一個新的 dataset,這個 dataset 含有的是源 dataset 中的 distinct 的 element。join(otherDataset,[numTasks]):
當有兩個 KV 的 dataset(K,V)和(K,W),返回的是(K,(V,W))的 dataset,numTasks 爲併發的任務數。cogroup(otherDataset,[numTasks]):
當有兩個 KV 的 dataset(K,V)和(K,W),返回的是(K,Seq[V],Seq[W])的 dataset,numTasks 爲併發的任務數。cartesian(otherDataset):
笛卡爾積簡單說就是 m*n。groupByKey(numTasks):
返回(K,Seq[V]),也就是 hadoop 中 reduce 函數接受的 key-valuelist。reduceByKey(func,[numTasks]):
就是用一個給定的 reduce func再作用在groupByKey產生的(K,Seq[V]),比如求和,求平均數。sortByKey([ascending],[numTasks]):
按照 key 來進行排序,是升序還是降序,ascending 是 boolean 類型。leftOuterJoin:
leftOuterJoin 類似於 SQL 中的左外關聯 left outer join,返回結果以前面的 RDD 爲主,關聯不上的記錄爲空。只能用於兩個 RDD 之間的關聯,如果要多個 RDD 關聯,多關聯幾次即可。
2.2 action 操作
count():
返回的是 dataset 中的 element 的個數。first():
返回的是 dataset 中的第一個元素。take(n):
返回前 n 個 elements,這個是driver program 返回的。takeSample(withReplacement,num,seed):
抽樣返回一個 dataset 中的 num 個元素,隨機種子 seed。reduce(func):
說白了就是聚集,但是傳入的函數是兩個參數輸入返回一個值,這個函數必須是滿足交換律和結合律的。collect():
一般在 filter 或者足夠小的結果的時候,再用 collect 封裝返回一個數組。saveAsTextFile(path):
把 dataset 寫到一個 text file 中,或者 hdfs,或者 hdfs 支持的文件系統中,spark 把每條記錄都轉換爲一行記錄,然後寫到 file 中。saveAsSequenceFile(path):
只能用在 key-value 對上,然後生成 SequenceFile 寫到本地或者 hadoop 文件系統。countByKey():
返回的是 key 對應的個數的一個 map,作用於一個 RDD。foreach(func):
對 dataset 中的每個元素都使用 func。
最新的 RDD Operations,請參考: RDD Operations
三、實驗案例之實時黑名單過濾
3.1 案例描述:
在一些企業中,比如小額貸款公司,需要做好風控,對那些信譽不好的用戶,我們需要設置黑名單,只要是黑名單中的用戶,我們就給過濾掉,禁止提供貸款服務。既然是實時
,必然用到 SparkStreaming,這裏採用 socketTextStream
,結合 nc
命令使用。由於是實驗,不方面提供真實數據,這裏一再簡化,可以簡單模擬一份數據,進行測試,原理是相同的。
注意:模擬的數據字段格式爲(id user),例如: 00001 張三。
3.2 實驗步驟:
1). 雙擊打開桌面 Xfce 終端,首先使用 nc
啓動一個監聽端口8888。
由於我們要使用 socketTextStream
傳入一個端口及對應的主機名,不先啓動端口會報錯。
nc -lk 8888
2). 再次雙擊打開桌面 Xfce 終端,啓動 spark-shell。
spark-shell
使用 import
導入依賴。
import org.apache.spark.SparkConf
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.Seconds
注意:如果是 spark-shell,那麼在進入 spark-shell 的時候,spark-shell 自動創建了一個 SparkContext 爲sc,那麼創建 StreamingContext 只需要用 sc 來 new 就可以了,這樣就不會出現多個sc 的衝突問題,否則會報錯。
創建StreamingContext,設置每一秒刷新一次。
val ssc = new StreamingContext(sc, Seconds(2))
設置需要過濾的黑名單,這裏設置兩個名字,您也可設置多個。
val bl = Array(("Jim", true),("hack", true))
設置並行度,這裏指定爲3。
val blRdd = ssc.sparkContext.parallelize(bl, 3)
設置主機名,端口號。
val st = ssc.socketTextStream("localhost", 8888)
對輸入數據進行轉換,(id, user) => (user, id user) ,以便對每個批次RDD,與之前定義好的黑名單進行leftOuterJoin操作。
val users = st.map { l => (l.split(" ")(1),l) }
調用左外連接操作leftOuterJoin,進行黑名單匹配,過濾掉。
val validRddDS = users.transform(ld => {
val ljoinRdd = ld.leftOuterJoin(blRdd)
val fRdd = ljoinRdd.filter(tuple => {
if(tuple._2._2.getOrElse(false)) {
false
} else {
true
}
})
val validRdd = fRdd.map(tuple => tuple._2._1)
validRdd
})
#打印白名單
validRddDS.print()
#執行
ssc.start()
#等待完成
ssc.awaitTermination()
此刻,你會看到每隔一秒不斷刷新。
接下來,回到第一次打開的 Xfce 終端,即監聽 8888 端口。
輸入以下內容:
0001 marry
0003 hack
0002 tom
同理繼續輸入一下內容:
0004 Jim
0005 John
0006 shiro
經過兩次的輸入,發現對黑名單裏的數據都過濾掉,實驗完畢。由於設置的刷新間隔太短您可能,看得不是很清楚,可以將間隔設置大一點,方便觀察。
四、總結
由於篇幅的原因,本節課主要介紹了Spark 的算子操作,包括lazy
和action
兩種,然後基於一個小案例進行加深學習,涉及到 SparkStreaming 的一些操作。更多的 SparkRDD 操作請參考:Spark 官網