如何将Rows插入已存在的数据集中。 显示的表格是我的数据的一个愚蠢的版本,我可以作为数据集使用。
每当两个连续行之间的时差跳过下一个整整一小时时,我想插入一个新行。除新时间之外的所有列都应与上面的行相同。
日期时间或日期&时间充足。我只是把它们放在我的例子中,以表明我可以访问所有这些。
我的一般想法是计算两行之间的小时跳过量,创建一个新数据集,将其与原始数据集连接,然后对其进行排序。
+--------+-------------------+----------+--------+
| status| datetime| date| time|
+--------+-------------------+----------+--------+
| start|2017-01-01 07:15:12|2017-01-01|07:15:12|
| init|2017-01-01 07:22:12|2017-01-01|07:22:12|
|A_status|2017-01-01 07:31:12|2017-01-01|07:31:12|
|B_status|2017-01-01 10:30:12|2017-01-01|10:30:12|
|C_Status|2017-01-01 11:15:12|2017-01-01|11:15:12|
+--------+-------------------+----------+--------+
+--------+-------------------+----------+--------+
| status| datetime| date| time|
+--------+-------------------+----------+--------+
| start|2017-01-01 07:15:12|2017-01-01|07:15:12|
| init|2017-01-01 07:22:12|2017-01-01|07:22:12|
|A_status|2017-01-01 07:31:12|2017-01-01|07:31:12|
|A_status|2017-01-01 08:00:00|2017-01-01|08:00:00|
|A_status|2017-01-01 09:00:00|2017-01-01|09:00:00|
|A_status|2017-01-01 10:00:00|2017-01-01|10:00:00|
|B_status|2017-01-01 10:30:12|2017-01-01|10:30:12|
|B_status|2017-01-01 11:00:00|2017-01-01|11:00:00|
|C_Status|2017-01-01 11:15:12|2017-01-01|11:15:12|
+--------+-------------------+----------+--------+
我的第一个想法是以小时计算时差,如果是> = 1,则在新数据集中生成该行数并将其连接到原始数据集。 问题是它没有检测到从B_status到C_status的跳过,因为它只有3/4小时。
val df9 = df3.withColumn("time_diff", ((unix_timestamp(lead($"datetime", 1).over(Window.orderBy("datetime"))) - unix_timestamp($"datetime"))/60/60)).show
我的下一个想法是提取时间字段的小时部分并减去它们。这将导致正确的线数,但需要额外处理从HH24到HH00的跳转。
我还读到了爆炸函数,因为这可能会生成具有相同数据的新行,但我还不知道这个函数是否适用于这种情况。
有人有任何提示或实施来帮助我吗?也许有一种更简单的方法来实现这一目标。祝周末愉快。
答案 0 :(得分:1)
您可以使用explode
功能获得所需的结果,但为此您需要hour, lead, Window, udf, unix_timestamp, select, SimpleDateFormat
和更多功能的复杂组合,这些功能将在下面说明。
鉴于dataframe
为
+--------+-------------------+----------+--------+
|status |datetime |date |time |
+--------+-------------------+----------+--------+
|start |2017-01-01 07:15:12|2017-01-01|07:15:12|
|init |2017-01-01 07:22:12|2017-01-01|07:22:12|
|A_status|2017-01-01 07:31:12|2017-01-01|07:31:12|
|B_status|2017-01-01 10:30:12|2017-01-01|10:30:12|
|C_Status|2017-01-01 11:15:12|2017-01-01|11:15:12|
+--------+-------------------+----------+--------+
只有status
和datetime
列非常重要,因为date
和time
columna可以从要更改的datetime
列中派生出来。所以你必须只选择两个,并将上一行的小时差异作为
val df2 = df.select($"status", unix_timestamp($"datetime").cast(TimestampType).as("datetime"), (hour(lead($"datetime", 1).over(Window.orderBy("datetime"))) - hour($"datetime")).as("hour"))
应该给你
+--------+---------------------+----+
|status |datetime |hour|
+--------+---------------------+----+
|start |2017-01-01 07:15:12.0|0 |
|init |2017-01-01 07:22:12.0|0 |
|A_status|2017-01-01 07:31:12.0|3 |
|B_status|2017-01-01 10:30:12.0|1 |
|C_Status|2017-01-01 11:15:12.0|null|
+--------+---------------------+----+
既然您有小时差异,就可以从datetime
值到小时差异日期时间获取日期时间数组,这可以通过以下方式完成将udf
函数定义为
def getDiffDateArray = udf((date : String, hour: Int, value : Int) => {
if((value - 1) > 0) {
var array = Array.empty[String]
for(time <- 0 to value){
val format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val originalDate = format.parse(date)
val calendar = Calendar.getInstance
calendar.setTimeInMillis(originalDate.getTime)
calendar.set(Calendar.HOUR_OF_DAY, hour+time)
if(time != 0){
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
}
array = array ++ Array(format.format(calendar.getTime))
}
array}
else Array(date)
})
您可以使用日期时间数组上的explode
函数,并通过执行以下操作获取date
和time
列
def getTimeFromeDateTime = udf((date: String) =>{
val parseFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
val timeFormat = new SimpleDateFormat("HH:mm:ss")
val time = parseFormat.parse(date)
timeFormat.format(time)
})
df2.withColumn("datetime", explode(getDiffDateArray($"datetime", hour($"datetime"), when($"hour".isNotNull, $"hour").otherwise(lit(0)))))
.drop("hour")
.withColumn("date", $"datetime".cast(DateType))
.withColumn("time", getTimeFromeDateTime($"datetime"))
.show(false)
这可以为您提供所需的结果
+--------+-------------------+----------+--------+
|status |datetime |date |time |
+--------+-------------------+----------+--------+
|start |2017-01-01 07:15:12|2017-01-01|07:15:12|
|init |2017-01-01 07:22:12|2017-01-01|07:22:12|
|A_status|2017-01-01 07:31:12|2017-01-01|07:31:12|
|A_status|2017-01-01 08:00:00|2017-01-01|08:00:00|
|A_status|2017-01-01 09:00:00|2017-01-01|09:00:00|
|A_status|2017-01-01 10:00:00|2017-01-01|10:00:00|
|B_status|2017-01-01 10:30:12|2017-01-01|10:30:12|
|C_Status|2017-01-01 11:15:12|2017-01-01|11:15:12|
+--------+-------------------+----------+--------+
我希望答案很有帮助