前言:
transform不是transformation,后者是对所有的转换算子的统称,transform也是transformation算子中的一个。transform算子的主要作用就是为了弥补Streaming没有提供的相关功能的操作,比如:一个DStream和RDD进行关联操作join,或者减少分区数量。
一、使用transform来完成分区减少coalsce的操作
dstream.transform(_.coalesce(newPartitionNum))
二、使用transform来完成DStream和RDD的join操作
计费系统,是电商必不可少的一个功能点。为了防止恶意的广告点击(假设商户A和B同时在某电商做了广告,A和B为竞争对手,那么如果A使用点击机器人进行对B的广告的恶意点击,那么B的广告费用将很快被用完),必须对广告点击进行黑名单过滤。黑名单的过滤可以是ID,可以是IP等等,黑名单就是过滤的条件,利用SparkStreaming的流处理特性,可实现实时黑名单的过滤实现。可以使用leftouter join 对目标数据和黑名单数据进行关联,将命中黑名单的数据过滤掉。
?:
/**
* 使用transform进行在线黑名单过滤
*
* 使用ip作为黑名单
* 27.19.74.143
* 110.52.250.126
* 数据的格式:
* 27.19.74.143##2016-05-30 17:38:20##GET /static/image/common/faq.gif HTTP/1.1##200##1127
*
*/
object Transform2BlacklistFileter {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setAppName("Transform2BlacklistFileter")
.setMaster("local[*]")
val ssc = new StreamingContext(conf, Seconds(2))
//准备黑名单
val blacklist:RDD[(String, Int)] = ssc.sparkContext.parallelize(
Map(
"27.19.74.143" -> 1,
"110.52.250.126" -> 1
).toList
)
//网络请求,包含了黑名单中的数据
val lines:DStream[String] = ssc.socketTextStream("bigdata01", 9999)
//数据示例
//27.19.74.143##2016-05-30 17:38:20##GET /static/image/common/faq.gif HTTP/1.1##200##1127
val ip2Info:DStream[(String, String)] = lines.map(line => {
val ip = line.substring(0, line.indexOf("##"))
val info = line.substring(line.indexOf("##") + 2)
(ip, info)
})
val filtered:DStream[(String, String)] = ip2Info.transform(infoRDD => {
// infoRDD.join(blacklist)//结果是黑名单中的数据,必须要
val joinedRDD:RDD[(String, (String, Option[Int]))] = infoRDD.leftOuterJoin(blacklist)
joinedRDD.filter{case (ip, (info, option)) => !option.isDefined}
.map{case (ip, (info, option)) => (ip, info)}
})
filtered.print()
ssc.start()
ssc.awaitTermination()
}
}