spark sql距离最近的假期

时间:2016-11-22 21:56:49

标签: sorting apache-spark hive apache-spark-sql datediff

在熊猫中,我有一个类似于

的功能
indices = df.dateColumn.apply(holidays.index.searchsorted)
df['nextHolidays'] = holidays.index[indices]
df['previousHolidays'] = holidays.index[indices - 1]

计算距离最近的假日的距离并将其存储为新列。

searchsorted http://pandas.pydata.org/pandas-docs/version/0.18.1/generated/pandas.Series.searchsorted.html对于大熊猫来说是一个很好的解决方案,因为它为我提供了下一个假期的索引,而没有高算法复杂度Parallelize pandas apply,例如这种方法比并行循环快得多。

如何在火花或蜂巢中实现这一目标?

1 个答案:

答案 0 :(得分:1)

这可以使用聚合来完成,但是这种方法比pandas方法具有更高的复杂性。但是您可以使用UDF实现类似的性能。它不会像熊猫一样优雅,但是:

假设这个假期数据集:

holidays = ['2016-01-03', '2016-09-09', '2016-12-12', '2016-03-03']
index = spark.sparkContext.broadcast(sorted(holidays))

数据框中2016年日期的数据集:

from datetime import datetime, timedelta
dates_array = [(datetime(2016, 1, 1) + timedelta(i)).strftime('%Y-%m-%d') for i in range(366)]
from pyspark.sql import Row
df = spark.createDataFrame([Row(date=d) for d in dates_array])

UDF可以使用pandas searchsorted,但需要在执行程序上安装pandas。 Insted你可以像这样使用plan python:

def nearest_holiday(date):
    last_holiday = index.value[0]
    for next_holiday in index.value:
        if next_holiday >= date:
            break
        last_holiday = next_holiday
    if last_holiday > date:
        last_holiday = None
    if next_holiday < date:
        next_holiday = None
    return (last_holiday, next_holiday)


from pyspark.sql.types import *
return_type = StructType([StructField('last_holiday', StringType()), StructField('next_holiday', StringType())])

from pyspark.sql.functions import udf
nearest_holiday_udf = udf(nearest_holiday, return_type)

可以与withColumn一起使用:

df.withColumn('holiday', nearest_holiday_udf('date')).show(5, False)

+----------+-----------------------+
|date      |holiday                |
+----------+-----------------------+
|2016-01-01|[null,2016-01-03]      |
|2016-01-02|[null,2016-01-03]      |
|2016-01-03|[2016-01-03,2016-01-03]|
|2016-01-04|[2016-01-03,2016-03-03]|
|2016-01-05|[2016-01-03,2016-03-03]|
+----------+-----------------------+
only showing top 5 rows