【问题标题】:how to get months,years difference between two dates in sparksql如何在sparksql中获取两个日期之间的月、年差
【发布时间】:2020-01-25 07:14:32
【问题描述】:

我收到错误:

org.apache.spark.sql.analysisexception: cannot resolve 'year'

我的输入数据:

1,2012-07-21,2014-04-09

我的代码:

val sqlContext = new org.apache.spark.sql.SQLContext(sc)
import sqlContext.implicits._
import org.apache.spark.sql.SaveMode
import org.apache.spark.sql._
import org.apache.spark.sql.functions._
case class c (id:Int,start:String,end:String)
val c1 = sc.textFile("date.txt")
val c2 = c1.map(_.split(",")).map(r=>(c(r(0).toInt,r(1).toString,r(2).toString)))
val c3 = c2.toDF();
c3.registerTempTable("c4")
val r = sqlContext.sql("select id,datediff(year,to_date(end), to_date(start)) AS date from c4")

如何解决上述错误?

我已经尝试了以下代码,但我在几天内就得到了输出,而且我需要几年后才能得到它

val r = sqlContext.sql("select id,datediff(to_date(end), to_date(start)) AS date from c4")

如果我可以使用 to_date 之类的任何函数来获取年份差异,请告诉我。

【问题讨论】:

  • 除以 365?还有一个日期部分允许您指定年份。请参阅docs.microsoft.com/en-us/sql/t-sql/functions/…Google 是您的朋友。
  • 感谢您的意见。我尝试使用 UDF 的 @Missy 除以 365
  • docs.microsoft.com 的链接指的是 T-SQL(即 SQL Server 中使用的过程语言),而不是 Spark。

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


【解决方案1】:

另一种在 spark sql 中将字符串转换为 dateType 并在列上应用sql dates and time functions 的简单方法,如下所示:

import org.apache.spark.sql.types._
val c4 = c3.select(col("id"),col("start").cast(DateType),col("end").cast(DateType))

c4.withColumn("dateDifference", datediff(col("end"),col("start")))
  .withColumn("monthDifference", months_between(col("end"),col("start")))
  .withColumn("yearDifference", year(col("end"))-year(col("start")))
  .show()

【讨论】:

  • 你好瑞诗凯诗。如果相差 9 年零 10 个月会发生什么情况。是否会将其四舍五入到 10 年?
  • @Bharath 不,它不会四舍五入。为此,请查看 Spark 文档以获取舍入功能,或者您可以为其创建单独的 UDF。
【解决方案2】:

当两个日期之间的天数小于 365 时,上述答案之一不会返回正确的年份。下面的示例提供了正确的年份并将月份和年份四舍五入到小数点后 2。

Seq(("2019-07-01"),("2019-06-24"),("2019-08-24"),("2018-12-23"),("2018-07-20")).toDF("startDate").select(
col("startDate"),current_date().as("endDate"))
.withColumn("datesDiff", datediff(col("endDate"),col("startDate")))
.withColumn("montsDiff", months_between(col("endDate"),col("startDate")))
.withColumn("montsDiff_round", round(months_between(col("endDate"),col("startDate")),2))
.withColumn("yearsDiff", months_between(col("endDate"),col("startDate"),true).divide(12))
.withColumn("yearsDiff_round", round(months_between(col("endDate"),col("startDate"),true).divide(12),2))
.show()

输出:

+----------+----------+---------+-----------+---------------+--------------------+---------------+
| startDate|   endDate|datesDiff|  montsDiff|montsDiff_round|           yearsDiff|yearsDiff_round|
+----------+----------+---------+-----------+---------------+--------------------+---------------+
|2019-07-01|2019-07-24|       23| 0.74193548|           0.74| 0.06182795666666666|           0.06|
|2019-06-24|2019-07-24|       30|        1.0|            1.0| 0.08333333333333333|           0.08|
|2019-08-24|2019-07-24|      -31|       -1.0|           -1.0|-0.08333333333333333|          -0.08|
|2018-12-23|2019-07-24|      213| 7.03225806|           7.03|         0.586021505|           0.59|
|2018-07-20|2019-07-24|      369|12.12903226|          12.13|  1.0107526883333333|           1.01|
+----------+----------+---------+-----------+---------------+--------------------+---------------+

您可以在以下 URL 找到完整的工作示例

https://sparkbyexamples.com/spark-calculate-difference-between-two-dates-in-days-months-and-years/

希望这会有所帮助。

学习愉快!!

【讨论】:

    【解决方案3】:
    val r = sqlContext.sql("select id,datediff(year,to_date(end), to_date(start)) AS date from c4")
    

    在上面的代码中,“year”不是数据框中的列,即它不是表“c4”中的有效列,这就是为什么在查询无效时抛出分析异常,查询无法找到“年”列。

    使用 Spark User Defined Function (UDF),这将是一种更强大的方法。

    【讨论】:

    • @AshSr SparkSQL 的 datediff() 函数在撰写本文时没有 interval 参数(或类似参数)。
    【解决方案4】:

    因为dateDiff 只返回天之间的差异。我更喜欢使用自己的 UDF。

    import java.sql.Timestamp
    import java.time.Instant
    import java.time.temporal.ChronoUnit
    
    import org.apache.spark.sql.functions.{udf, col}
    import org.apache.spark.sql.DataFrame
    
    def timeDiff(chronoUnit: ChronoUnit)(dateA: Timestamp, dateB: Timestamp): Long = {
        chronoUnit.between(
          Instant.ofEpochMilli(dateA.getTime),
          Instant.ofEpochMilli(dateB.getTime)
        )
    }
    
    def withTimeDiff(dateA: String, dateB: String, colName: String, chronoUnit: ChronoUnit)(df: DataFrame): DataFrame = {
        val timeDiffUDF = udf[Long, Timestamp, Timestamp](timeDiff(chronoUnit))
        df.withColumn(colName, timeDiffUDF(col(dateA), col(dateB)))
    }
    

    然后我称之为数据帧转换。

    df.transform(withTimeDiff("sleepTime", "wakeupTime", "minutes", ChronoUnit.MINUTES)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-07
      • 2022-10-02
      • 1970-01-01
      • 2014-12-06
      • 2016-05-07
      • 2021-11-15
      • 2013-07-23
      • 2013-07-17
      相关资源
      最近更新 更多