数据帧转换

时间:2016-08-24 19:06:53

标签: scala apache-spark

我是Spark和Scala的新手。我有一个拥有大量数据的数据框。架构就像这样。

让我们称之为dataframe empDF

       id   name      emp_id  code  date
       1    Andrew    D01     C101  2012-06-14
       2    James     D02     C101  2013-02-26
       3    James     D02     C102  2013-12-29
       4    James     D02     C101  2010-09-27
       5    Andrew    D01     C101  2013-10-12
       6    Andrew    D01     C102  2011-10-13

我从数据库中将此数据作为DataFrame[Row]对象读取。现在我必须执行以下步骤:

对于每行代码C101,必须设置大于1的行,对于其他代码级别应为0.如果没有以前的记录, 级别设置为1。如果存在比该记录早两年或更多年的先前记录,则级别设置为2。 在此步骤之后,数据框应该如下所示

       id   name      emp_id  code  date         level
       1    Andrew    D01     C101  2012-06-14     2
       2    James     D02     C101  2013-02-26     2
       3    James     D02     C102  2012-12-29     0
       4    James     D02     C101  2010-09-27     1
       5    Andrew    D01     C101  2009-10-12     1
       6    Andrew    D01     C102  2010-10-13     0

第一行和第二行的级别为2,因为此员工的记录较旧,两行之间的日期差异超过两年。级别为1的行是因为没有前一个日期的记录,级别为“0”的行是因为我们已将所有代码标记为0级别而不是C101

现在对于级别为2的行,我们必须检查如果代码C102在去年适用于那些员工,如果应用然后将级别设置为3,否则不要更改级别。在最终结果数据帧中,应删除除代码C101之外的所有行。

完成上述两个步骤后,生成的数据框应如下所示:

     id name    emp_id  code  date       level
     1  Andrew  D01     C101  2012-06-14   2
     2  James   D02     C101  2013-02-26   3
     4  James   D02     C101  2010-09-27   1
     5  Andrew  2013    C101  2013-10-12   1

请注意,第一行的级别为2,因为该员工在去年内没有C102,但第二行在去年内有C102。 如何使用数据框api在Scala中执行此操作,以及mapflatmapreduce等函数?

2 个答案:

答案 0 :(得分:2)

您可以使用window functions

\

答案 1 :(得分:0)

// Input data
val df = {
    import org.apache.spark.sql._
    import org.apache.spark.sql.types._
    import scala.collection.JavaConverters._
    import java.time.LocalDate

    val simpleSchema = StructType(
        StructField("id", IntegerType) ::
        StructField("name", StringType) ::
        StructField("emp_id", StringType) ::
        StructField("code", StringType) ::
        StructField("date", DateType) :: Nil)

    val data = List(
        Row(1, "Andrew", "D01", "C101", java.sql.Date.valueOf(LocalDate.of(2012, 6, 14))),
        Row(2, "James", "D02", "C101", java.sql.Date.valueOf(LocalDate.of(2013, 2, 26))),
        Row(3, "James", "D02", "C102", java.sql.Date.valueOf(LocalDate.of(2013, 12, 29))),
        Row(4, "James", "D02", "C101", java.sql.Date.valueOf(LocalDate.of(2010, 9, 27)))
    )    

    spark.createDataFrame(data.asJava, simpleSchema)
}
df.show()
// Filter and level calculation.
val df2 = df.filter(col("code") === "C101").
    withColumn("level", when(datediff(col("date"), min(col("date")).over(Window.partitionBy("emp_id"))) >= 365 * 2, 2).otherwise(1))
df2.show()