初探Spark,DataFrame中使用Time Window实现Count window

背景:最近工作中碰到一个需求,需要使用一个spark job进行离线数据同步,将每天所有车的心跳HB数据中的指标A进行统计,得到响应一个统计结果,然后入库,对于1个完全没有接触过spark的人来说,要在一周内完成这个job,可以说真是充满了挑战。

job的逻辑的核心算法,是这样:每一台车约有550条HB,以15条为宽度,以5条为间距,移动的去统计计算,即1-15条数据进行一次算法判断得到一个结果,6-20条进行一次算法判断得到一个结果,11-25条数据进行一次算法判断得到一个结果…直至第550条。

难点:看到这个算法描述,首先想到的是使用滑动窗口,来解决此问题。然后去对spark进行技术调研,发现spark在进行离线计算时,现在的主流是将数据读取成DataFrame或者DataSet结构去进行操纵,我这个需求中,选择的是使用DataFrame。但是深入调研(google+baidu)发现,针对rdd/DataFrame/DataSet,都没有现成的技术能够直接实现我算法的核心逻辑;倒是Spark Streaming中的window可以满足的需求,但是只能用于实时计算,不能用于离线计算。

只能在DataFrame中的唯一window:Time Window上多动心思。
关于DataFrameTime Window大家可以搜到很多相关的文章,概括起来就是,如果想使用这个窗口,你的数据中首先得要有一个类型为TimeStamp的列,然后每条数据的这一列都是等距的,比如间隔是1s,1min或者1hour;如果满足这个条件,就可以设置一个。
我的数据虽然理论上是HB数据,数据都是带有数据发送时间,而且是都以1min为间距的等距数据,但是实际上车子在发送HB时会有数据丢失,或者因为网络延迟造成的一些误差,因此没法直接使用。

最后我想到了去给我的数据追加上一列,使得数据能够满足Time Window的使用要求。

我的原始数据大概是这个样子:

车辆编号(vid)心跳数据发送时间(send_time)发动机温度(temperature)
1112020-05-24 00:00:0080
1112020-05-24 00:01:0176
1112020-05-24 00:03:0678
1112020-05-24 00:07:0081
1112020-05-24 00:10:0077
1112020-05-24 00:11:0082
2222020-05-24 00:00:0080
2222020-05-24 00:01:0176
2222020-05-24 00:03:0678
2222020-05-24 00:07:0081
2222020-05-24 00:10:0077
2222020-05-24 00:11:0082

相关的实现代码:

//读取文件得到DataFrame,数据格式类似于上述数据
val dfData = spark.read.orc(filePath)
	.select("vin", "send_time", "temperature")
//并且为了能使用time window,基于row_number()函数给每行添加一个类型为TimestampType的标记
val dfDataWithTag = dfData
      .withColumn("TAG",  row_number().over(Window.partitionBy("vin").orderBy(col("send_time"))).cast(TimestampType))

追加之后的数据变为

车辆编号(vid)心跳数据发送时间(send_time)发动机温度(temperature)TAG
1112020-05-24 00:00:00801970-01-01 08:00:01.0
1112020-05-24 00:01:01761970-01-01 08:00:02.0
1112020-05-24 00:03:06781970-01-01 08:00:03.0
1112020-05-24 00:07:00811970-01-01 08:00:04.0
1112020-05-24 00:10:00771970-01-01 08:00:05.0
1112020-05-24 00:11:00821970-01-01 08:00:06.0
2222020-05-24 00:00:00801970-01-01 08:00:01.0
2222020-05-24 00:01:01761970-01-01 08:00:02.0
2222020-05-24 00:03:06781970-01-01 08:00:03.0
2222020-05-24 00:07:00811970-01-01 08:00:04.0
2222020-05-24 00:10:00771970-01-01 08:00:05.0
2222020-05-24 00:11:00821970-01-01 08:00:06.0

每条记录都追加上了一个间隔为1s的TAG字段
然后就可以对数据使用time window进行滑动统计了

val resDf = dfDataWithTag 
	  .groupBy(col("vid"),functions.window(col("TAG"),"15seconds","5 seconds","1 seconds"))
      .agg(udafFunction(col("temperature")).as("resData"))
      .sort("vid","window.start")
      .select("vid","window.start","window.end","resData")

此处的udafFunction我使用的是自定义的聚合函数UDAF,关于UDAF的部分大家也可以自行查看相关内容,如果是比较简单的业务场景,也可以直接使用spark中现成的一些agg聚合函数。

以上就是Time Window实现Count Window的相关代码了。

在此次编码中,将遇到的其他的spark中block住我比较久的一些东西,再另写(水)一篇博客进行记录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值