Join 在python中按时间(TimestampType)连接两个spark数据帧

Join 在python中按时间(TimestampType)连接两个spark数据帧,join,apache-spark,apache-spark-sql,pyspark,Join,Apache Spark,Apache Spark Sql,Pyspark,我有两个数据帧,我想基于一列连接它们,但要注意的是,这列是一个时间戳,为了连接记录,时间戳必须在一定的偏移量(5秒)内。更具体地说,dates\u df中带有date=1/3/2015:00:00的记录应与带有time=1/3/2015:00:00的events\u df连接,因为两个时间戳之间的间隔均在5秒内 我正试图用python spark实现这种逻辑,这是非常痛苦的。人们是如何在spark中进行这种连接的 我的方法是在dates\u df中添加两个额外的列,以确定下时间戳和上时间戳的边界

我有两个数据帧,我想基于一列连接它们,但要注意的是,这列是一个时间戳,为了连接记录,时间戳必须在一定的偏移量(5秒)内。更具体地说,
dates\u df
中带有
date=1/3/2015:00:00
的记录应与带有
time=1/3/2015:00:00
events\u df
连接,因为两个时间戳之间的间隔均在5秒内

我正试图用python spark实现这种逻辑,这是非常痛苦的。人们是如何在spark中进行这种连接的

我的方法是在
dates\u df
中添加两个额外的列,以确定
下时间戳
上时间戳
的边界,并执行条件联接。这就是它失败的地方,更具体地说:

joined_df = dates_df.join(events_df, 
    dates_df.lower_timestamp < events_df.time < dates_df.upper_timestamp)

joined_df.explain()

我确实使用
explain()
触发了SQL查询,以了解它是如何完成的,并在python中复制了相同的行为。首先,这里介绍如何使用SQL spark执行相同的操作:

dates_df.registerTempTable("dates")
events_df.registerTempTable("events")
results = sqlContext.sql("SELECT * FROM dates INNER JOIN events ON dates.lower_timestamp < events.time and  events.time < dates.upper_timestamp")
results.explain()
日期\u df.寄存器可清空(“日期”)
事件\u df.寄存器可清空(“事件”)
results=sqlContext.sql(“选择*从日期内部加入dates.lower\u timestamp
这是可行的,但问题是如何在python中实现,因此解决方案似乎只是简单的连接,后面跟着两个过滤器:

joined_df = dates_df.join(events_df).filter(dates_df.lower_timestamp < events_df.time).filter(events_df.time < dates_df.upper_timestamp)
joined\u df=dates\u df.join(events\u df).filter(dates\u df.lower\u timestamp

joined_df.explain()
生成与sql spark
结果相同的查询。explain()
因此我假设这就是事情的处理方式。

虽然一年后,但可能会帮助其他人

正如你所说,在你的情况下,完全笛卡尔积是疯狂的。您的匹配记录将在时间上接近(5分钟),因此,如果您首先根据记录的时间戳将记录分组到存储桶,然后将该存储桶上的两个数据帧合并,然后应用过滤器,则可以利用这一点并节省大量时间。使用该方法会使Spark使用SortMergeJoin而不是CartesianProduct,从而大大提高性能

这里有一个小警告——你必须同时匹配这个桶和下一个桶

最好在我的博客中用工作代码示例进行解释(Scala+Spark 2.0,但也可以在python中实现相同的功能…)


Spark SQL似乎能优雅地处理它
results=sqlContext.sql(“选择*从日期内部加入dates.lower\u timestamp
成功了。只是想一想:将此日期\u df.lower\u时间戳<事件\u df.time<日期\u df.upper\u时间戳更改为类似于日期\u df.lower\u时间戳<事件\u df.time和事件\u df.time<日期\u df.upper\u时间戳。他们没有理由这样做differently@ayan:我也尝试过这种方法,但效果不一样。看起来像个bug……我不懂Python,但在Scala中应该很简单。您甚至不需要创建新列。我将创建一个UDF,在时间戳上加上或减去秒数,然后重新运行。然后在两个UDF调用的结果之间加入一个时间戳。不要链接到随机的博客文章(即使是你的),在这里写下示例,然后链接到你的博客。
+-----+--------------------+
| name|                date|
+-----+--------------------+
|day_1|2015-01-01 00:00:...|
|day_2|2015-01-02 00:00:...|
|day_3|2015-01-03 00:00:...|
|day_4|2015-01-04 00:00:...|
+-----+--------------------+

+--------------------+-------+
|                time|  event|
+--------------------+-------+
|2015-01-03 00:00:...|meeting|
+--------------------+-------+


+-----+--------------------+--------------------+--------------------+--------------------+-------+
| name|                date|     lower_timestamp|     upper_timestamp|                time|  event|
+-----+--------------------+--------------------+--------------------+--------------------+-------+
|day_3|2015-01-03 00:00:...|2015-01-02 23:59:...|2015-01-03 00:00:...|2015-01-03 00:00:...|meeting|
|day_4|2015-01-04 00:00:...|2015-01-03 23:59:...|2015-01-04 00:00:...|2015-01-03 00:00:...|meeting|
+-----+--------------------+--------------------+--------------------+--------------------+-------+
dates_df.registerTempTable("dates")
events_df.registerTempTable("events")
results = sqlContext.sql("SELECT * FROM dates INNER JOIN events ON dates.lower_timestamp < events.time and  events.time < dates.upper_timestamp")
results.explain()
joined_df = dates_df.join(events_df).filter(dates_df.lower_timestamp < events_df.time).filter(events_df.time < dates_df.upper_timestamp)