目录
4.2.3 处理逻辑(1)----filter类型,timeWindowAll
4.2.4 处理逻辑(2)----AllWindowFunction实现UV去重
1.知识点
- scala样例类
- source api: readTextFile
- DataStream.timeWindowAll的使用(比较KeyedStream.timeWindow)
windowAll,不能设置并行度,并行度1;window ,可设置并行度,返回AllWindowedStream
timeWindowAll,并行度为1,返回AllWindowedStream
AllWindowedStream.apply(AllWindowFunction),返回DataStream
- AllWindowedStream.apply 传入全窗口函数AllWindowFunction
的使用 - AllWindowFunction的案例
2.业务目标
滚动输出最近1小时内的PV.
窗口:1小时
指标:点击量
3.流程心法
总体流程:创建输入、输出样例类---->主Object
主object:
1) 创建执行环境,设置并行度、时间语义(事件时间)等参数
2) transform map转换输入样例类,有序数据设置watermark,无序数据根据乱序时间设置watermark
3)不分组,直接timeWindowAll计算(无法并行)
4)传入UV全窗口函数
5)UV简单全窗口函数实现原理:
定义一个set类型,直接往里放userid,不用比对了,自动count值
4.模块详解
4.1 创建输入输出样例类
//定义输入样例类
case class UserBehavior(userId: Long, itemId: Long, categoryId: Int, behavior: String, timestamp: Long)
// 定义输出Uv统计样例类
case class UvCount(windowEnd: Long, count: Long)
4.2 主object实现
4.2.1 创建执行环境并添加数据源
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
env.setParallelism(6)
4.2.2 Datastream map转换为输入样例类
// 从文件中读取数据,获取resources中的文件,相对路径
val resource = getClass.getResource("/UserBehavior.csv")
print(resource.getPath)
val inputStream: DataStream[String] = env.readTextFile(resource.getPath)
// 转换成样例类类型并提取时间戳和watermark
val dataStream: DataStream[UserBehavior] = inputStream
.map(data => {
val arr = data.split(",")
UserBehavior(arr(0).toLong, arr(1).toLong, arr(2).toInt, arr(3), arr(4).toLong)
}) //No implicits found for parameter evidence$8:,需要引入 createTypeInformation,或者直接引入import org.apache.flink.streaming.api.scala._
.assignAscendingTimestamps(_.timestamp * 1000L)
4.2.3 处理逻辑(1)----filter类型,timeWindowAll
val uvStream = dataStream
.filter(_.behavior == "pv")
.timeWindowAll( Time.hours(1) ) // 直接不分组,基于DataStream开1小时滚动窗口
.apply( new UvCountResult() ) //apply传入全窗口函数
4.2.4 处理逻辑(2)----AllWindowFunction实现UV去重
自定义个全窗口函数,用一个set结构保存所有userid
缺点是:1)全窗口 2)SET. 数据量大很容易溢出
// 自定义实现全窗口函数,用一个Set结构来保存所有的userId,进行自动去重。 1)全窗口 2)set,数据量大直接溢出了,那么如何优化呢? 布隆过滤器
class UvCountResult() extends AllWindowFunction[UserBehavior, UvCount, TimeWindow]{
override def apply(window: TimeWindow, input: Iterable[UserBehavior], out: Collector[UvCount]): Unit = {
//最简单的思路,定义一个set 类型,直接去重,不用比对了,自动count值
var userIdSet = Set[Long]()
//遍历全窗口的所有数据,把userId添加到set中,自动去重
for(userBehavior <- input ){
userIdSet += userBehavior.userId
}
out.collect(UvCount(window.getEnd,userIdSet.size))
}
}