1、PV(page view)
即页面浏览量;用户每1次对网站中的每个网页访问均被记录1次。用户对同一页面的多次访问,访问量累计。
2.UV(unique visitor) 网站独立访客数
指访问某个站点或点击某条新闻的不同IP地址的人数。
在同一天内,uv 只记录第一次进入网站的具有独立IP的访问者,在同一天内再次访问该网站则不计数。独立IP访问者提供了一定时间内不同观众数量的统计指标,而没有反应出网站的全面活动。
衡量网站流量一个最简单的指标,就是网站的页面浏览量(Page View,PV)。 用户每次打开一个页面便记录 1 次 PV,多次打开同一页面则浏览量累计
。一般来说, PV 与来访者的数量成正比,但是
PV
并不直接决定页面的真实来访者数量,如同一个来访者通过不断的刷新页面,也可以制造出非常高的 PV。
我们知道,用户浏览页面时,会从浏览器向网络服务器发出一个请求(Request),网络服务器接到这个请求后,会将该请求对应的一个网页(Page
)发送给浏览器, 从而产生了一个 PV
。所以我们的统计方法,
可以是从 web 服务器的日志中去提取对应的页面访问然后统计,就向上一节中的做法一样;也可以直接从埋点日志中提 取用户发来的页面请求,从而统计出总浏览量。
输入数据:
import org.apache.flink.api.common.functions.{AggregateFunction, MapFunction}
import org.apache.flink.api.common.state.{ValueState, ValueStateDescriptor}
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.KeyedProcessFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.WindowFunction
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector
import scala.util.Random
// 定义输入样例类
case class UserBehavior(userId: Long,
itemId: Long,
categoryId: Int,
behavior: String,
timestamp: Long )
// 网站总浏览量
object PageView {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
//env.setParallelism(1)
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
val inputStream: DataStream[String] = env.readTextFile("D:\\Mywork\\workspace\\Project_idea\\UserBehaviorAnalysis0903\\HotItemsAnalysis\\src\\main\\resources\\UserBehavior.csv")
//转换成样例类类型,并提取时间戳
val dataStream = inputStream.map(data => {
val arr: Array[String] = data.split(",")
UserBehavior(arr(0).toLong, arr(1).toLong, arr(2).toInt, arr(3), arr(4).toLong)
}).assignAscendingTimestamps(_.timestamp * 1000L)
val pvStream = dataStream
.filter(_.behavior == "pv")
// .map {data => ("pv", 1L) } //定义一个Pv字符串作为Dummy key(哑key)
.map(new MyMapper())
.keyBy(_._1) //所有数据分到同一个组
.timeWindow(Time.hours(1)) //1H滚动窗口
.aggregate(new PvCountAgg(), new PvCountWindowResult())
val totalPvStream = pvStream
.keyBy(_.windowEnd)
.process(new TotalPvCountResult())
totalPvStream.print()
env.execute()
}
}
//自定义Mapper,随机生成分组的Key
class MyMapper() extends MapFunction[UserBehavior, (String, Long)] {
override def map(value: UserBehavior): (String, Long) = {
(Random.nextString(10), 1L)
}
}
//自定义预聚合函数
class PvCountAgg() extends AggregateFunction[(String, Long), Long, Long]{
override def createAccumulator(): Long = 0L
override def add(value: (String, Long), accumulator: Long): Long = accumulator + 1
override def getResult(accumulator: Long): Long = accumulator
override def merge(a: Long, b: Long): Long = a + b
}
//定义输出PV统计的样例类
case class PvCount(windowEnd: Long, count: Long)
//自定义窗口函数
class PvCountWindowResult() extends WindowFunction[Long, PvCount, String, TimeWindow]{
override def apply(key: String, window: TimeWindow, input: Iterable[Long], out: Collector[PvCount]): Unit = {
out.collect(PvCount(window.getEnd, input.head))
}
}
class TotalPvCountResult() extends KeyedProcessFunction[Long, PvCount, PvCount] {
lazy val totalPvCountResultState: ValueState[Long]= getRuntimeContext.getState(new ValueStateDescriptor[Long]("total-Pv", classOf[Long]))
override def processElement(value: PvCount, ctx: KeyedProcessFunction[Long, PvCount, PvCount]#Context, out: Collector[PvCount]): Unit = {
totalPvCountResultState.update(totalPvCountResultState.value() + value.count)
//注册一个Windowed+1S后触发定时器
ctx.timerService().registerEventTimeTimer(value.windowEnd + 1)
}
override def onTimer(timestamp: Long, ctx: KeyedProcessFunction[Long, PvCount, PvCount]#OnTimerContext, out: Collector[PvCount]): Unit = {
val totalPvCount = totalPvCountResultState.value()
out.collect(PvCount(ctx.getCurrentKey, totalPvCount)) //(windowEnd: Long, count: Long)
totalPvCountResultState.clear()
}
}
输出结果:
12> PvCount(1511668800000,47298)
7> PvCount(1511665200000,48022)
6> PvCount(1511679600000,50838)
10> PvCount(1511672400000,44499)
1> PvCount(1511676000000,48649)
11> PvCount(1511683200000,52296)
7> PvCount(1511694000000,13)
4> PvCount(1511661600000,41890)
4> PvCount(1511686800000,52552)
4> PvCount(1511690400000,48292)