目录
一:项目需求
1.1、需求说明
-
弹幕的日志格式为:
IP,UID,Time,URL,Referrer(访问来源),status code(状态码) - 示例:
- 将敏感词放在一个文件里
- 示例:
- 每1分钟统计一次10分钟内发布的弹幕内容出现敏感词汇超过5次的用户ID,并在HBase中存储出现的次数。
注:只是个小Demo,所以为了减少后续等待程序运行时间,我将UID设置为100个,以及弹幕信息多为含敏感词的以便于快速达到5个值
1.2、准备工作
- pom文件
<dependencies> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>2.11.12</version> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-streaming_2.11</artifactId> <version>2.3.4</version> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-streaming-kafka-0-10_2.11</artifactId> <version>2.3.4</version> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.42.Final</version> </dependency> <dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-client</artifactId> <version>1.4.10</version> </dependency> <dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-server</artifactId> <version>1.4.10</version> </dependency> </dependencies>
二:项目实现
package com.yxf.kafka
import org.apache.hadoop.hbase.TableName
import org.apache.hadoop.hbase.client.Put
import org.apache.hadoop.hbase.util.Bytes
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribe
import org.apache.spark.streaming.kafka010.KafkaUtils
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import org.apache.spark.streaming.{Minutes, Seconds, StreamingContext}
object kafkaStreaming2 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local[3]").setAppName("kafkaSteaming2")
val ssc = new StreamingContext(conf,Minutes(1))
val topic = Array("logsys")
val KafkaParams = Map[String,Object](
"bootstrap.servers" -> "node01:9092,node02:9092,node03:9092",
"key.deserializer" -> classOf[StringDeserializer],
"value.deserializer" -> classOf[StringDeserializer],
"group.id" -> "kafkaStreaming",
"auto.offset.reset" -> "latest",
"enable.auto.commit" -> (false: java.lang.Boolean)
)
val DStream = KafkaUtils.createDirectStream(
ssc,
PreferConsistent,
Subscribe[String, String](topic, KafkaParams)
)
val value: DStream[(String, Iterable[String])] = DStream
//过滤掉状态码不为200的数据
.filter(line => line.value().split(" ")(11).equals("200"))
//将DStream转化为(UID,弹幕)格式
.map(line => {
(line.value().split(" ")(3),
if (line.value().split(" ")(7).equals("\"GET")) {
line.value().split(" ")(8).split("=")(1)
} else {
line.value().split(" ")(8).split("/")(1)
})
})
//groupByKey将同一用户发的所有弹幕保存到一个可迭代的RDD中
.groupByKeyAndWindow(Minutes(10),Minutes(1))
//读取文件中的敏感词
val file = ssc.sparkContext.textFile("SparkStreaming\\in")
//将敏感词放入Array数组中便于后面遍历
val words: Array[String] = file.flatMap(_.split(" ")).collect()
/**
* 接下来的目标是:将DStream转化为以UID为key,以发布敏感弹幕的次数作为value
* 一:需要用到transform算子对DStream内部的RDD进行转换;
* 二:将map算子将(String, Iterable[String])转化为(String, Int);
* 三:用filter算子过滤value大于5的用户
*
* */
val value1: DStream[(String, Int)] = value
//transform算子对DStream内部的RDD进行转换
.transform(rdd =>
//map算子将(String, Iterable[String])转化为(String, Int)
rdd.map(x => (x._1, {
var sum = 0
//遍历原RDD中的value
for (elem <- x._2) {
//遍历文件中的敏感词
for (word <- words) {
//判断弹幕中是否包含敏感词,如果包含则加1
if (elem.contains(word)) {
sum = sum + 1
}
}
}
//将int类型的sum返回
sum
}))
//过滤value大于5的
.filter(_._2>=5))
/**
* 此时我们拿到的数据就是DStream[(UID,发布敏感弹幕次数)]的类型了
* */
//入库HBase
value1.foreachRDD(rdd => rdd.foreachPartition(partitionRecoreds =>{
val connection = HbaseUtil.getHbaseConnection
val tablename = TableName.valueOf("table2")
val table = connection.getTable(tablename)
partitionRecoreds.foreach(data =>{
val put = new Put(Bytes.toBytes(data._1))
put.addColumn(Bytes.toBytes("sensitive"),Bytes.toBytes("count"),Bytes.toBytes(data._2.toString))
table.put(put)
})
})
)
ssc.start()
ssc.awaitTermination()
}
}
三:结果展示
- 在等待了30分钟后,我们查看hbase中的结果(部分)
四:结束语
- 写的比较简单,在不考虑性能的情况下可以参考下。
- 自动生成日志的代码和flume采集日志没有展示出来,主要是相对来说比较简单。
- 如果哪里写的不好评论区可以探讨下。