Pyspark 获取Spark数据框中两个日期之间的所有日期

Pyspark 获取Spark数据框中两个日期之间的所有日期,pyspark,apache-spark-sql,Pyspark,Apache Spark Sql,我有一个DF,其中有bookingDt和arrivalDt列。我需要找出这两个日期之间的所有日期 示例代码: df=spark.sparkContext.parallelize( [Row(vyge_id=1000,bookingDt='2018-01-01',arrivalDt='2018-01-05'))。toDF() diffDaysDF=df.withColumn(“diffDays”,datediff('arrivalDt','bookingDt')) diffDaysDF.show(

我有一个DF,其中有
bookingDt
arrivalDt
列。我需要找出这两个日期之间的所有日期

示例代码:

df=spark.sparkContext.parallelize(
[Row(vyge_id=1000,bookingDt='2018-01-01',arrivalDt='2018-01-05'))。toDF()
diffDaysDF=df.withColumn(“diffDays”,datediff('arrivalDt','bookingDt'))
diffDaysDF.show()
代码输出:

+----------+----------+-------+--------+
|抵达时间|预订时间|维吉id |天数|
+----------+----------+-------+--------+
|2018-01-05|2018-01-01|   1000|       4|
+----------+----------+-------+--------+
我尝试的是找到两个日期之间的天数,并使用
timedelta
函数和
explode
函数计算所有日期

dateList=[str(bookingDt+timedelta(i))表示范围内的i(diffDays)]
预期输出:

基本上,我需要为
bookingDt
arrivalDt
之间的每个日期创建一个DF,包括这两个日期

+----------+----------+-------+----------+
|arrivalDt | bookingDt | vyge | id | txnDt|
+----------+----------+-------+----------+
|2018-01-05|2018-01-01|   1000|2018-01-01|
+----------+----------+-------+----------+
|2018-01-05|2018-01-01|   1000|2018-01-02|
+----------+----------+-------+----------+
|2018-01-05|2018-01-01|   1000|2018-01-03|
+----------+----------+-------+----------+
|2018-01-05|2018-01-01|   1000|2018-01-04|
+----------+----------+-------+----------+
|2018-01-05|2018-01-01|   1000|2018-01-05|
+----------+----------+-------+----------+

好吧,你可以做以下事情

创建仅包含日期的数据框:

日期_df
#第一次
预订日期
和最后一次
到达日期

然后将这些df连接到中间条件:

df.join(dates_df, 
  on=col('dates_df.dates').between(col('df.bookindDt'), col('dt.arrivalDt'))
.select('df.*', 'dates_df.dates')
它可能比使用
explode
的解决方案工作得更快,但是您需要确定此df的开始和结束日期。
10年df将只有3650条记录,不需要太多担心。

只要您使用Spark 2.1版或更高版本,您就可以利用我们在使用时可以使用的事实:

  • 创建长度等于
    diffDays
  • 在“
    ”和“
    上拆分此字符串,将其转换为大小为
    diffDays
  • 用于分解此数组及其索引
  • 最后使用将索引值天数添加到
    bookingDt
代码:

导入pyspark.sql.f函数
diffDaysDF.withColumn(“repeat”,f.expr(“split(repeat(',',',,diffDays),,,'))”)\
.选择(“*”,f.posexplode(“重复”)。别名(“txnDt”,“val”))\
.drop(“重复”、“val”、“diffDays”)\
.带列(“txnDt”,f.expr(“日期添加(预订日期,txnDt)”)\
.show()
#+----------+----------+-------+----------+
#|arrivalDt | bookingDt | vyge | id | txnDt|
#+----------+----------+-------+----------+
#|2018-01-05|2018-01-01|   1000|2018-01-01|
#|2018-01-05|2018-01-01|   1000|2018-01-02|
#|2018-01-05|2018-01-01|   1000|2018-01-03|
#|2018-01-05|2018-01-01|   1000|2018-01-04|
#|2018-01-05|2018-01-01|   1000|2018-01-05|
#+----------+----------+-------+----------+
正如@vvg建议的那样:

#我想Bookindt的日期范围包括arrivalDt,
#否则,您必须找到Bookindt和arrivalDt的唯一日期的交叉点
日期_df=df.select('bookindDt').distinct()
dates_df=dates_df.with ColumnRename('Bookindt','day_of_listing')
listing_days_df=df.join(dates_df,on=dates_df.day_of_listing.between(df.bookindDt,df.arrivalDt))
输出:

+----------+----------+-------+-------------------+
|arrivalDt | bookingDt | vyge | id |上市日||
+----------+----------+-------+-------------------+
|2018-01-05|2018-01-01|   1000|2018-01-01         |
+----------+----------+-------+-------------------+
|2018-01-05|2018-01-01|   1000|2018-01-02         |
+----------+----------+-------+-------------------+
|2018-01-05|2018-01-01|   1000|2018-01-03         |
+----------+----------+-------+-------------------+
|2018-01-05|2018-01-01|   1000|2018-01-04         |
+----------+----------+-------+-------------------+
|2018-01-05|2018-01-01|   1000|2018-01-05         |
+----------+----------+-------+-------------------+

ForSpark 2.4+可用于创建一个数组,其中包含
bookingDt
arrivalDt
之间的所有日期。然后可以分解此阵列

从pyspark.sql导入函数为F
df=df\
.withColumn('bookingDt',F.col('bookingDt')。cast('date'))\
.withColumn('arrivalDt',F.col('arrivalDt')。cast('date'))
df.带列('txnDt',F.爆炸(F.expr('sequence(预订、到达、间隔1天)))\
.show()
输出:

+-------+----------+----------+----------+
|vyge|u id | bookingDt | arrivalDt | txnDt|
+-------+----------+----------+----------+
|   1000|2018-01-01|2018-01-05|2018-01-01|
|   1000|2018-01-01|2018-01-05|2018-01-02|
|   1000|2018-01-01|2018-01-05|2018-01-03|
|   1000|2018-01-01|2018-01-05|2018-01-04|
|   1000|2018-01-01|2018-01-05|2018-01-05|
+-------+----------+----------+----------+

这正是我想要的。。但是否有可能改善这一点。似乎相当复杂。一种方法可能是创建一个日期数据框,与使用此方法建议的@Volodymyr连接。基本上选择最小预订日期和最大到达日期,计算以天为单位的差异,并创建一个数据帧,其中所有日期都在这两个日期之间。