什么是' pyspark.sql.functions.window'功能' startTime'参数呢?

时间:2017-01-09 05:18:59

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

在官方文档中只有一个简单的例子:

  

startTime是相对于1970-01-01 00:00:00 UTC的偏移量   从哪个开始       窗口间隔。例如,为了让每小时翻滚窗口开始15分钟       过去一小时,例如12:15-13:15,13:15-14:15 ...... startTime提供15 minutes

但我想知道它如何适用于所有论点。

例如:

ts_list = map(lambda x: datetime.datetime(2017, 1, 9, 9, 0, 10) + datetime.timedelta(seconds=x), range(30))
rdd = spark.sparkContext.parallelize(ts_list).map(lambda x: (x, 1))
df = spark.createDataFrame(rdd, schema=['dt', 'val'])
win = df.groupBy(window("dt", "5 seconds", '4 seconds', '3 seconds')).agg(sum("val").alias("sum"))
pprint.pprint(win.select(win['window']['start'].cast('string').alias('start'),
                         win['window']['end'].cast('string').alias('end')).collect())

输出:

[Row(start=u'2017-01-09 09:00:19', end=u'2017-01-09 09:00:24'),                 
 Row(start=u'2017-01-09 09:00:35', end=u'2017-01-09 09:00:40'),
 Row(start=u'2017-01-09 09:00:27', end=u'2017-01-09 09:00:32'),
 Row(start=u'2017-01-09 09:00:07', end=u'2017-01-09 09:00:12'),
 Row(start=u'2017-01-09 09:00:31', end=u'2017-01-09 09:00:36'),
 Row(start=u'2017-01-09 09:00:39', end=u'2017-01-09 09:00:44'),
 Row(start=u'2017-01-09 09:00:11', end=u'2017-01-09 09:00:16'),
 Row(start=u'2017-01-09 09:00:23', end=u'2017-01-09 09:00:28'),
 Row(start=u'2017-01-09 09:00:15', end=u'2017-01-09 09:00:20')]

为什么?

2 个答案:

答案 0 :(得分:4)

它与您的数据何时开始无关。当然第一个窗口只会出现在该窗口中有一些数据之前。但startTime与您的数据无关。 正如文档所述,startTime是相对于1970-01-01 19:00:00 UTC的偏移,用于开始窗口间隔。 如果你创建一个这样的窗口:
w = F.window(“date_field”,“7天”,startTime ='6天')

spark将从1970-01-06开始生成7天的窗口:

1970-01-06 19:00:00,1970-01-13 19:00:00
1970-01-13 19:00:00,1970-01-20 19:00:00
1970-01-20 19:00:00,1970-01-27 19:00:00
...
2017-05-16 19:00:00,217-05-23 19:00:00
(如果你继续计算你到达这个日期) ...
但是,您只会看到与数据帧日期相关的窗口。 19:00:00是因为我的时区是-05
如果你创建一个这样的窗口:

w = F.window(“date_field”,“7天”,startTime ='2天')

从1970-01-02开始,

spark将生成7天的窗口:

1970-01-02 19:00:00,1970-01-09 19:00:00
1970-01-09 19:00:00,1970-01-16 19:00:00
...
2017-05-19 19:00:00,2017-05-26 19:00:00
(如果你继续计算你到达这个日期)
...

您再次只能看到与数据框日期相关的窗口
那么,如何计算数据窗口的开始日期?
你只需要计算自1970-01-01以来你的开始日期,然后除以窗口的长度并取余数。这将是抵消天数的开始时间。


我将用一个例子来解释它: 从 2017-05-21 开始,你需要你的窗户,窗户的长度为7天。我将为该示例创建一个虚拟数据帧。

row = Row("id", "date_field", "value")
df = sc.parallelize([
row(1, "2017-05-23", 5.0),
row(1, "2017-05-26", 10.0),
row(1, "2017-05-29", 4.0),
row(1, "2017-06-10", 3.0),]).toDF()

start_date = datetime(2017, 5, 21, 19, 0, 0) # 19:00:00 because my 
timezone 
days_since_1970_to_start_date =int(time.mktime(start_date.timetuple())/86400)
offset_days = days_since_1970_to_start_date % 7

w = F.window("date_field", "7 days", startTime='{} days'.format(
                                        offset_days))

df.groupby("id", w).agg(F.sum("value")).orderBy("window.start").show(10, False)

你会得到:

+---+------------------------------------------+----------+
|id |window                                    |sum(value)|
+---+------------------------------------------+----------+
|1  |[2017-05-21 19:00:00, 2017-05-28 19:00:00]|15.0      |
|1  |[2017-05-28 19:00:00, 2017-06-04 19:00:00]|4.0       |
|1  |[2017-06-04 19:00:00, 2017-06-11 19:00:00]|3.0       |
+---+------------------------------------------+----------+

答案 1 :(得分:1)

让我们一步一步走。

  • 您的数据从2017-01-09 09:00:10开始:

    df.orderBy("dt").show(3, False)
    
    +---------------------+---+
    |dt                   |val|
    +---------------------+---+
    |2017-01-09 09:00:10.0|1  |
    |2017-01-09 09:00:11.0|1  |
    |2017-01-09 09:00:12.0|1  |
    +---------------------+---+
    
  • 第一个完整小时为2017-01-09 09:00:00.0

    from pyspark.sql.functions import min as min_, date_format
    (df
       .groupBy()
       .agg(date_format(min_("dt"), "yyyy-MM-dd HH:00:00"))
       .show(1, False))
    
    +-----------------------------------------+
    |date_format(min(dt), yyyy-MM-dd HH:00:00)|
    +-----------------------------------------+
    |2017-01-09 09:00:00                      |
    +-----------------------------------------+
    
  • 因此,第一个窗口将从2017-01-09 09:03:00开始,2017-01-09 09:00:00 + startTime(3秒),结束于2017-01-09 09:08:002017-01-09 09:00:00 + startTime + windowDuration)。

    此窗口为空([09:03:0009:08:00)范围内没有数据。

  • 第一个(和第二个)数据点将落入下一个窗口,即[09:00:07.009:00:12.0),从2017-01-09 09:00:00 + startTime开始+ 1 * slideDuration

    win.orderBy("window.start").show(3, False)
    
    +---------------------------------------------+---+
    |window                                       |sum|
    +---------------------------------------------+---+
    |[2017-01-09 09:00:07.0,2017-01-09 09:00:12.0]|2  |
    |[2017-01-09 09:00:11.0,2017-01-09 09:00:16.0]|5  |
    |[2017-01-09 09:00:15.0,2017-01-09 09:00:20.0]|5  |
    +---------------------------------------------+---+
    

    2017-01-09 09:00:00

  • 中的startTime的下一个窗口启动slideDuration + n + n * 1..