0905-广告点击量实时统计
需求七:实时维护黑名单
7.1 需求概述
从Kafka获取实时数据,对每个用户的点击次数进行累加并写入MySQL,当一天之内一个用户对一个广告的点击次数超过100次时,将用户加入黑名单中。
7.2 简要运行流程
- 根据实时获取的数据, 批量更新用户点击次数表
- 更新完之后, 再从表中查出操作异常的用户
- 将操作异常的用户ID加入到黑名单表中
7.3 具体运行流程
7.4 代码实现
7.4.1 加载并转换用户数据集
val sparkConf = new SparkConf().setAppName("adver").setMaster("local[*]")
val sparkSession = SparkSession.builder().config(sparkConf).enableHiveSupport().getOrCreate()
val streamingContext: StreamingContext = new StreamingContext(sparkSession.sparkContext, Seconds(5))
val kafka_brokers = ConfigurationManager.config.getString(Constants.KAFKA_BROKERS)
val kafka_topics = ConfigurationManager.config.getString(Constants.KAFKA_TOPICS)
// kafka参数配置
val kafkaParam = Map(
"bootstrap.servers" -> kafka_brokers,
"key.deserializer" -> classOf[StringDeserializer],
"value.deserializer" -> classOf[StringDeserializer],
"group.id" -> "group1",
"auto.offset.reset" -> "latest",
"enable.auto.commit" -> (false: java.lang.Boolean)
// auto.offset.reset
// latest: 先去Zookeeper获取offset,如果有,直接使用,如果没有,从最新的数据开始消费;
// earlist: 先去Zookeeper获取offset,如果有,直接使用,如果没有,从最开始的数据开始消费
// none: 先去Zookeeper获取offset,如果有,直接使用,如果没有,直接报错
)
// 消费kafka中的数据
// adRealTimeDStream: DStream[RDD RDD RDD ...] RDD[message] message: key value
val adRealTimeDStream: InputDStream[ConsumerRecord[String, String]] = KafkaUtils.createDirectStream[String, String](
streamingContext,
LocationStrategies.PreferConsistent,
ConsumerStrategies.Subscribe[String, String](Array(kafka_topics), kafkaParam)
)
// adRealTimeValueDStream: DStream[RDD RDD RDD...] RDD[String] String : timestamp province city userid adid
val adRealTimeValueDStream: DStream[String] = adRealTimeDStream.map(item => item.value())
7.4.2 过滤掉已经上黑名单的用户
// 从拿到的实时数据中过滤掉黑名单中的用户
// adRealTimeFilterDStream:DStream[RDD RDD RDD...]
// RDD[String]
// String : timestamp province city userid adid
val adRealTimeFilterDStream: DStream[String] = adRealTimeValueDStream.transform {
logRDD =>
val blackLIstArray: Array[AdBlacklist] = AdBlacklistDAO.findAll()
val userIdArray: Array[Long] = blackLIstArray.map(item => item.userid)
val filteredRDD: RDD[String] = logRDD.filter {
case log =>
val logSplit = log.split(" ")
val userId = logSplit(3).toLong
!userIdArray.contains(userId)
}
filteredRDD
}
7.4.3 对实时数据进行统计,更新点击次数表
// 对实时用户点击广告数据进行计数
// multiKey2OneDStream: DStream[RDD,RDD...]
// RDD : (key, value)
// key : datekey_userId_adId
// value : 1
val multiKey2OneDStream: DStream