通过Spark数据帧迭代获取日期月份

时间:2018-01-08 11:39:28

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

我有一个问题案例,根据输入日期迭代最近36个月。目前使用Scala,通过DataFrame我得到时间戳字段的最大值。例如:

val vGetDate = hc.read.format("filodb.spark").option("database","YYYYY").option("dataset","XXX").load().agg(max("inv_date").alias("max_date"))

例如,日期为2017-12-01 00:00:00

现在我需要迭代才能获得过去36个月的日期。

注意,我使用Spark 1.4而不是Cassandra和FiloDB。

1 个答案:

答案 0 :(得分:0)

如果您可以访问Spark 1.5+,则可以使用yearmonth功能轻松实现,但由于您只能访问Spark 1.4,因此您必须复制其功能在UDF中,如下:

val year = udf {
  (s: String) =>
    java.sql.Timestamp.valueOf(s).getYear
}

val month = udf {
  (s: String) =>
    java.sql.Timestamp.valueOf(s).getMonth
}

def monthDiff(a: Column, b: Column): Column =
  (year(a) - year(b)) * 12 + (month(a) - month(b))

然后,您可以将此UDF与where子句一起使用,以便在此示例中过滤您的DataFrame

final case class Data(date: String)

val df = spark.createDataFrame(Seq(Data("2017-04-01 00:00:00")))

val since = lit("2018-01-01 00:00:00")

assert(df.where(monthDiff(since, $"date") < 36).count == 1)

assert(df.where(monthDiff(since, $"date") < 4).count == 0)

关于迭代的需求,使用Spark DataFrame API时通常要采用的是声明性方法,使用groupBy语句进行聚合你的钥匙。例如,您的原始查询可以表示如下():

val vGetDate = 
  hc.read.format("filodb.spark").option("database","YYYYY").option("dataset","XXX").load().
  where(monthDiff(lit(startDate), "inv_date")).
  groupBy(concat(year("inv_date"), lit("-"), lpad(month("inv_date"), 2, "0"))).
  agg(max("inv_date").alias("max_date"))

在这里,您为所有组生成最新日期(由分组键定义为年份和月份,格式为yyyy-MM "inv_date"startDate不超过36个月{{1} }}