Spark Dataframe - 窗口功能 - 滞后和放大插入引线&更新输出

时间:2018-01-11 11:08:09

标签: scala apache-spark pyspark apache-spark-sql spark-dataframe

我需要使用Windowing函数Lag and Lead对数据帧执行以下操作。

对于每个Key,我需要在最终输出中执行以下Insert和update

插入条件
1.默认情况下,LAYER_NO = 0,需要写入输出 2.如果COL1,COL2,COL3的值与其宝贵记录相对应,则该记录需要写入输出。

示例:key_1 with layer_no = 2,COL3中值从400更改为600

更新条件
1.如果COL1,COL2,COL3的值与其先前记录的值没有任何变化,但在" DEPART列"中有变化,则需要在输出中更新该值。

示例:key_1 with layer_no = 3,COL1,COL2,COL3没有任何变化,但DEPART列中的值有变化为" xyz" ,所以这需要在输出中更新 2.在插入带有layer_no = 0

的记录后,甚至应该按顺序更新LAYER_NO
    val inputDF = values.toDF("KEY","LAYER_NO","COl1","COl2","COl3","DEPART")

    inputDF.show()   
    +-----+--------+----+----+----+------+
    |  KEY|LAYER_NO|COL1|COL2|COL3|DEPART|
    +-----+--------+----+----+----+------+
    |key_1|       0| 200| 300| 400|   abc|->default write
    |key_1|       1| 200| 300| 400|   abc|
    |key_1|       2| 200| 300| 600|   uil|--->change in col3,so write
    |key_1|       2| 200| 300| 600|   uil|
    |key_1|       3| 200| 300| 600|   xyz|--->change in col4,so update
    |key_2|       0| 500| 700| 900|   prq|->default write
    |key_2|       1| 888| 555| 900|   tep|--->change in col1 & col 2,so write
    |key_3|       0| 111| 222| 333|   lgh|->default write
    |key_3|       1| 084| 222| 333|   lgh|--->change in col1,so write
    |key_3|       2| 084| 222| 333|   rrr|--->change in col4,so update
    +-----+--------+----+----+----+------+

预期产出:

outputDF.show()
+-----+--------+----+----+----+------+
|  KEY|LAYER_NO|COl1|COl2|COl3|DEPART|
+-----+--------+----+----+----+------+
|key_1|       0| 200| 300| 400|   abc|
|key_1|       1| 200| 300| 600|   xyz|
|key_2|       0| 500| 700| 900|   prq|
|key_2|       1| 888| 555| 900|   tep|
|key_3|       0| 111| 222| 333|   lgh|
|key_3|       1| 084| 222| 333|   rrr|
+-----+--------+----+----+----+------+

1 个答案:

答案 0 :(得分:2)

我们需要定义两个Window来达到您预期的输出。一个用于检查DEPART列中的更改,第二个用于检查COL1COL3之和的差异。

import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions.Window

val w_col = Window.partitionBy("KEY", "COL1", "COL2", "COL3").orderBy("LAYER_NO")
                  .rowsBetween(Window.unboundedPreceding, Window.unboundedFollowing)
val w_key = Window.partitionBy("KEY").orderBy("LAYER_NO")

然后我们只需用正确的值替换DEPART列中的值,并将数据过滤到滞后总和与当前列总和(以及LAYER_NO === 0行)不同的行。最后,我们按排名替换LAYER_NO

inputDF.withColumn("DEPART", last("DEPART").over(w_col))
   .withColumn("row_sum",($"COL1" + $"COL2" + $"COL3"))
   .withColumn("lag_sum", lag($"row_sum",1).over(w_key))
   .filter($"LAYER_NO" === 0 || not($"row_sum" === $"lag_sum"))
   .withColumn("LAYER_NO", rank.over(w_key)-1)
   .drop("row_sum", "lag_sum").show()
+-----+--------+----+----+----+------+
|  KEY|LAYER_NO|COl1|COl2|COl3|DEPART|
+-----+--------+----+----+----+------+
|key_1|       0| 200| 300| 400|   abc|
|key_1|       1| 200| 300| 600|   xyz|
|key_2|       0| 500| 700| 900|   prq|
|key_2|       1| 888| 555| 900|   tep|
|key_3|       0| 111| 222| 333|   lgh|
|key_3|       1| 084| 222| 333|   rrr|
+-----+--------+----+----+----+------+