00:00
接下来呢,我们是要好好练一下这个AG。所以我们再取new一个class,叫window。Agree it还是叫test吧,我们单独举一个例子,大家知道我们在电商的实际场景里边有一个很常见的统计指标,那就是PV和UV啊,那大家知道这个PV和UV应该怎么去统计呢?呃,简单来讲的话,PV那其实就跟我们那个count是一样的。来一个统计一次嘛,对吧,来一个就就叠加一次,来一个就叠加一次,所以这个其实比我们前面讲到的这个平均数还要简单,就跟我们做那个word countt一样吗?其实都不用包装了,不用map成一个user一个一,一个user一个1AT方法里边啊,只要来一个value,我把这个累加器加一不就完了吗?对吧,每来一个就加一,每来一个就加一,最后我输出这个累加器到底有几个输出几不就完了吗?啊,所以这个PV特别的简单啊啊那另外在电商里边还有一个常见的指标,那是UVUV稍微麻烦一点,因为它要做去虫。
01:06
那我们能想到像UV这一个要做驱虫的这种方式,我们用什么去做驱虫呢?当然一种方法是我可以把所有的数据都收集齐,收集齐了之后,然后挨个去比对,如果出现过的话,哎,这个就不算了,没出现过的话,哎,加一这个方法是可以,但是呢,稍微有点麻烦,我们可以直接利用一些特殊的数据结构,增量的实现这个功能,比如说哈希set,因为set有一个特点,它就本身是驱虫的嘛。UV的话是u visitor,单一访客数,独立访客数啊,啊,那就是每一个user只统计一次,所以我们就根据user来保存吗?来了一个访问数据,我就把它当前的user信息保存到set里边,下一次再来的时候,我直接把它添加到set里边,如果要是重复的话,那不就相当于没用吗?还是一个吗?最后我只要看一下这个set里边有多少用户,这不就是我的UV吗?
02:03
所以接下来我们其实用这个aggregate function可以非常方便的统计当前的PV和UV,那干脆我们就把这个PVUV直接放在一起来做测试吧,我们用另外一个指标啊,我们统计的是什么呢?我们干脆啊统计PV和UV。两者。相除。得到,大家想这个PV除以UV,这得到的是个什么东西啊?这个其实也还是有一些实际的意义的。PV相当于是。不排除重复的点击,重复的访问所有的数据,访问次数UV呢,哎,是访问的用户的个数,那这么一除是不是就是平均每个用户的访问次数啊,诶,所以这个可能代表了一个网站的用户年度,或者说用户的普遍的这个活跃度啊,所以这也算是有一些实际的含义啊,有一些这个项目里边确实还真的是有这样的一个指标去统计的啊,那所以接下来两者相除得到。
03:09
迎接用户。活跃度。啊,那这个前面的话跟一开始啊做的这个操作是完全一样的。先把抄的都抄过来,然后接下来我们这个就PV,最后啊xecute还是写出来,中间那就是统计PVUV,然后相除了,就先算一个PV,然后再算一个UV,呃,然后再再两个再再分别合起来做一个统计,其实没必要。大家会想到这其实就是一个过程啊,我们统计PV的时候,也就在统计UV啊,然后我最后只要开了窗口,哎,这里面我们是开窗啊。其实PVUV都是基于一段时间去统计的,没有人是说,哎,从我这个项目上线开始啊,呃,到目前为止所有的不停的一个统计啊,当然我们是有这个的总用户数啊,类似于这样的一个统计啊,啊,但是这个东西其实它这个增长是非常的缓慢啊,一般情况下统计出来之后,实时性的要求就没有那么高了,我们这里边主要是开窗口,还是给大家测这个窗口的用法。
04:15
B、当前我们的做法就是。所有数据。放在一起。统计,因为大家知道统计一个网站的p vov的时候,其实对于这个用户来讲也就不重要了啊,当然你如果要是按照分别按照用户来统计的话,那个叫每个用户的访问频次,就是我们前面讲的那就不是,那就不是PVUV了,那你UV还要对用户去重啊,啊,那你最后统计出来不就每个用户只有一个一个访问嘛,那就没有意义了,对吧?啊,所以我们这是所有数据放在一起统计PV和UV。那这里面就涉及到一个问题啊,我们现在。然后统计先T拜,然后开窗嘛,T拜T拜什么呢。
05:03
这种情况下,如果说我们所有数据就是要放在一起统计的话,那这个没什么好说的,那就指明一个K就完了,比方说目前的K指名为处,所有的数据就都是同一组了,我们直接把它放在一起去做统计啊,但是有要这样的话,这不又变成并行度变一了吗?全放到一个分区去处理了吗?诶,这是所谓的数据倾斜的问题,如果在实际项目当中的话,我们可以怎么样呢?诶我们可以先把它分成几组。比方说你统计PV的时候啊,我先根据每个user的访问量,或者我按照每个URL的访问量先做一个统计,然后把统计的结果呢啊,再全放到一组去合在一起,那个时候数据量就少多了嘛,就不会出现大量数据,海量数据全涌到一个分区里面去做计算了,所以这个就有点儿像什么呢?就是我们现在本来是那个海量的数据啊同时到来。如果你一开始就把它分到同一组的话,哎,那就变成了一下子汇总到一个分区里面去。
06:03
而现在的这个做法呢,可以是。如果数据倾斜的啊,比方说我按照user或者按照URL,甚至我可以自定义分区,你如果觉得它这个数据倾斜了,不均匀,有些URL访问量特别大,或者有些user的那个点击量特别大,那那这个时候怎么办呢?你就自定义这个分区规则,然后把它做一个平均分配。然后分别统计出来之后,我再把它汇集到同一个分区。并行度变一把,把当前的这个最后的结果加起来,哎,这是处理这个预偏移的这个常见的用法啊,啊,我们这里边就不给大家详细展开去说了啊,那这里边我们想要做的是先把它放在一起统计,那么就开窗,For event time Windows,然后点on。十。然后接下来,哎,那自然就是一个aggregate了,既然我们这么说了嘛,带来这个可能稍微有点麻烦啊,我干脆把它直接提炼到外边来,我们单独去实现一个这样的自定义的类,我们来看看这个东西到底长什么样子啊。
07:09
啊,那当然了,之前我们都是滚动窗口,你如果想测一下这个滑动窗口也是一样的啊,比方说我们测这个Ding in time Windows。这边当然就要给另外的一个参数,比方说十秒钟的窗口,那我们每隔两秒滑动一次吧。然后接下来就是。自定义一个方式。好,接下来public static plus啊,那这里我们把这个叫成什么名吧?呃,我们就叫成average PV吧,啊,因为看起来有点像一个平均的一个,每个人的访问量一样,对吧?呃,就把把PV给按照user平均了一下,我们就叫average PV,然后接下来implement aggregate function。三个。
08:00
就是之前我们直接在这儿匿名类的话,就是是直接就给我们补全了,现在你如果在外面的话还得自己写,但这个有好处,就是你对它的认识会更加的深刻一些,它的三个参数,首先是input,现在还是event没变,然后第二个是ACC空间聚合状态,我们现在要什么呢?我们现在首先统计PV。其实就是一个计数器嘛,哎,那所以当前我们要的是一个一个长整型的值,对吧,只要有一个长整形的数,就可以把它这个当前的PV统计出来了,然后统计UV呢,UV麻烦一点,我们要的是一个是一个哈希set。啊,所以当前我们是一个哈希哈希set和一个长整形值,那我们干脆把这个定义成一个。奇怪一点的,一个二元组吧。Two,然后一个长整形值和一个啊set。当然了,里边的类型应该是string,把user放进来嘛,啊,这是我们的空间的状态。
09:05
所以大家要注意啊。就是用长整形值保存PV数。Four。Har sheet。做都为B重,诶这是我们的累加器ACC,然后接下来。这个定义好了,最后还有一个输出的类型,输出类型的话,其实这个就很简单,我们最后不就是要一个他们俩的比值吗?它们的平均数吗?哎,Double吧,这个这个可以带小数点,要平均嘛,直接把它放在这就完事了,好看一下。要实现这四个方法到底该怎么写?首先create accumulator,创建累加器的时候要有一个初始化的过程,一开始的时候这里面没什么好好初始化的,对吧?这不就是零吗?长整形肯定就是零嘛,0L。
10:02
然后另外这个西set那里初始化一下new一个对不对,New一个哈set啊这里边既然我们这个类型已经指定是string了,那这写不写都行啊,直接扭出来完事。接下来是ADD,每来一个数据都会掉,这里的ADD的方法,那我们应该是怎么样呢?每。来。一条。数据,那应该是PV个数加一,然后是怎么样的,然后将user。放入阿西ET。中驱虫啊,哎,那所以接下来我们要做的操作那个甲乙简单,我们最后直接加上就行了,那关键是我们这里的accumulator。目前的这个状态,它里边的哈希set,哈希set是F1和一个at操作啊,value.user at进来,然后接下来return的时候。
11:02
返回一个更新之后的状态,返回的是TEMP2OF,然后accumul点。F0是当前的个数加一,然后后面是accumul减F1。就是我们添加了这个一个user之后的当前的哈希set放在这儿。这就是我们这个每来一条数据处理的过程,对吧,核心的流程就是这样。哎,我们只要考虑清楚我们要的状态是什么,然后每来一条数据到底要做什么更改,这样的话就搞清楚了。啊,然后最后考虑的是等到窗口结束的时候,输出什么窗口复发值。输出DV和UV的比值。啊,那大家知道加我根本就不用算啊,因为你这个算完了之后没用啊,我们只要有这两个状态就完了嘛,是到最后才做一个最终的计算就完事了,那这个最终的计算也非常的简单,这不就是直接。
12:07
aumulator.F0。我们前面这个数,然后直接去除以accumul减一。哈西set的再直接去除下不就完事了吗?啊,当然这里还报错,因为。我们要的是一个double类型对吧。直接一个转了之后,那肯定的除法最后得到结果就变成double了,对吧,这个精度肯定是按double来计算,然后最后还有一个这个,呃,末制方法,末制方法不写也行啊,那这个我们就偷懒了,好我们这样就搞定了,这就是我们定义的。啊,一个计算PVUV比值,平均每个用户活跃度的,按照窗口定义的这样一个方法啊,那接下来我们有一个average PV,把它创建出来,然后做一个打印图。为了看的更加的清晰一点啊,我们在前面把这个stream也打印出来吧。
13:06
这里边能看到我们到底哪些数据,然后看前到底统计出来的是一个什么样的一个PV,这样的话就看的能够明显一点。好,运行一下。这里产生了哦,三条数据,然后这里边。这里边是1.0,然后后面呢,呃,又产生了两条数据carry啊,然后是2.0。哎,大家看后面变成了2.5啊,不停的在在涨。就是平均的这个用户访问的数量在涨,涨到了3.33啊,然后又变成了2.52.5。可以从这里总结出什么状况吗?就是为什么是这样的一个结果呢?我们来停一下啊,它一直在跳,我们就看看现在的这个结果吧,他为什么长这个样子呢?哎,首先我们看一下啊,一开始的这三条数据,这里是。啊,BOB1条数据,CARRY1条数据啊,然后Bob又一条数据,那为什么这里的这个PV除以UV得到的是一个1.0呢?
14:07
这里本身有的这个个数应该是数据是有三条,然后当前的用户应该是有两个,哎,就这里边如果按这个算的话,算这个比值应该是1.5才对,哎,那那为什么是这样一个1.0的一个结果呢。大家要注意啊,当前我们并不是收集数据的时候,就直接把这三条数据都收集起来了。啊,因为大家看八秒钟的时候,直接就输出了一个结果,八秒钟的时候有十秒钟关闭的窗口吗。回忆一下当时我们窗口怎么定义的呀,这是滑动窗口。滚动窗口的话,这个简单是十秒钟滚动一次,那滑动窗口是什么呢?滑动窗口是。零到十秒一个窗口。下一个窗口呢,滑两秒,那应该是二到12秒。
15:03
再下一个窗口是。自到14秒。所以大家会发现,只要是所有的偶数秒都应该会啊,就是十秒以后啊,都应该会关一个窗口。事实上就是十秒之前的偶数秒也会关窗的啊,正常来讲都会关的,但那个06.57秒这个来的时候,为什么零六秒没关窗呢?因为零六秒之前的窗口没数据啊,最早的一个窗口都是零六秒的窗口啊,所以大家看现在这个关窗关的最早的一个窗口是是哪个窗口呢?其实是08.602,这个数据来了之后,那是不是零八秒的那个窗口要关了呀,所以当前关的这个最早的窗口其实是。十点十秒钟一个啊,47分,这是零八啊,所以那应该是46分。58秒。
16:01
到10:47。零八秒,大家看是不是最早关的是这个窗口啊?十秒钟一个嘛。在这个窗口里边有几条数据呢?47分零六秒47分07.587是不是都在这个范围内啊,八秒062就不属于这个窗口了,所以一共有几条数据呢?两条数据几个用户呢?两个用户一除是不是1.0啊啊,所以它这个含义是这样的啊,现在就把我们之前那个水位线啊,就是窗口什么时候触发,这也可以简单的测一下,看到这个行为了,这就啊,就是当前它的这个含义是因为我们那个没有延迟嘛,我们不是那个DURATION0嘛,当然它那个正常来讲有有一毫秒的延迟啊,那个我们就不再讨论了啊,所以我们就直接看这个秒数就可以了,就是08.602来了之后,当前大家就认为诶时间就到了八秒了,所以他要关。
17:03
八秒钟的窗口。那关掉的是。46分58秒到47分零八秒的这十秒窗口里边包含了两条数据。那这条数据又在哪里呢?这条数据在下一个窗口啊,那下一个窗口是哪里呢?那就是47分零八秒到47分18秒嘛。那是滚动窗口,现在是滑动窗口,两秒钟滑一次,那下一个窗口很快就到了,两秒钟47分整到。47分十秒。到47分十秒,所以大家看下一次这个触发窗口输出结果的时候,什么时候输出呢?来了10.609这个数据的时候,水位线auto mark是不是已经超过十秒了,超过十秒是不是这个十秒钟结束的窗口就该关了,哎,所以接下来就该统计了啊,那到底有几条数据呢?我们看一下啊,十秒钟窗口这条数据不算之前的数据是不是都应该算啊?
18:03
呃,四四十七分整到47分十秒嘛,这些都算啊,从第一条数据这个都算啊,啊,所以它就是有重复数据嘛,前面这两条数据,你第一个窗口也要算,后面窗口也要算啊,所以到底有几条数据呢?四条数据几个用户呢?Carry bob2个用户,所以是2.0。啊,同样道理,下一个窗口关窗的时间点应该是12秒,哎,那应该统计的是47分零二秒到47分12秒的所有数据,那这个还是所有的都都包含在里边啊,那所以就是前面的这些数据都在都在里边了,那我们看一下诶,现在多了一个marry,多了一个MARY3个用户了,然后一共有六条数据,那刚好这个六除以三还是二是吧,这个没变啊啊,那所以大家看到其实你就可以一个一个去考虑,后来它会涨到2.5,还会变成3.33。其实大家看后面大部分就变成2.5了,为什么变成2.5呢?
19:02
啊,这个其实就是我们当时那个测试生成数据的机制导致的嘛,我们是一秒钟生成一个窗口,长度十秒钟,那正常来讲不就里边就是十个数吗?十个数然后总共是四个不同的U字选择,对吧?哎,那大部分情况下,呃,我们十个数随机的话,可能四个数都应该能随机到,那正常来讲是不是就都是2.5啊。啊,所以大家会看到你如果测的多的话,后面有可能还会出现就是3.33什么的,因为十个数,然后有可能只出现了三个,甚至运气好的话,可能会出现5.0和10.0,但概率很小啊,大部分都是2.5了。这个我们就练习到这里。
我来说两句