火花时间戳过滤器在大于一天的范围内不起作用

时间:2018-06-27 09:08:58

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

我正在使用pyspark 2.3.0版本。 我正在过滤时间戳列上的数据帧。

|-requestTs:时间戳记(nullable = true)

当我在日间时间范围内进行过滤时,效果很好。 当我在2天范围内覆盖过滤器时,它不会返回所有记录。 我尝试了几种方法:

        df1 = df.filter(df["requestts"] >= sqlf.lit(startDatestr)) \
           .filter(df["requestts"] <= sqlf.lit(endDatestr))

        dates = (startDatestr, endDatestr)

        q1 = "unix_timestamp(requestts) BETWEEN unix_timestamp('{0}', 'yyyy-MM-dd HH:mm:ss') AND unix_timestamp('{1}', 'yyyy-MM-dd HH:mm:ss')".format(
            *dates)

        df1 = df.where(q1)

其中

startDatestr: 2018-06-26 07:00:00
endDatestr: 2018-06-26 21:40:00

当我计算返回的记录时

after date filter, count is :1168940768

如果我扩大搜索范围(因此希望有更多或相等的记录数),如:

startDatestr: 2018-06-25 11:00:00
endDatestr: 2018-06-26 21:40:00

我得到的记录数量要少得多。

我很困惑这可能是什么原因,以及按时间戳进行过滤的最佳方法是什么。 以及我如何考虑时区。

1 个答案:

答案 0 :(得分:0)

您的查询应该可以使用。我只是在pyspark shell上尝试过。

>>> from datetime import datetime
>>> import pyspark.sql.functions as F

>>> columns = ['id', 'ts']
>>> vals = [
...     (1, datetime(2018, 6, 26)),
...     (2, datetime(2018, 6, 27)),
...     (3, datetime(2018, 6, 28)),
...     (4, datetime(2018, 6, 29)),
...     (5, datetime(2018, 6, 30))
... ]
>>> df = spark.createDataFrame(vals, columns)

>>> df.show()
+---+-------------------+
| id|                 ts|
+---+-------------------+
|  1|2018-06-26 00:00:00|
|  2|2018-06-27 00:00:00|
|  3|2018-06-28 00:00:00|
|  4|2018-06-29 00:00:00|
|  5|2018-06-30 00:00:00|
+---+-------------------+

>>> df.printSchema()
root
 |-- id: long (nullable = true)
 |-- ts: timestamp (nullable = true)

以下是与您类似的查询:

>>> df.filter(df['ts'] >= F.lit('2018-06-27 00:00:00')) \
...     .filter(df['ts'] < F.lit('2018-06-29 00:00:00')).show()
+---+-------------------+
| id|                 ts|
+---+-------------------+
|  2|2018-06-27 00:00:00|
|  3|2018-06-28 00:00:00|
+---+-------------------+

您还可以使用逻辑运算符一次执行两个过滤器:

>>> df.filter((df['ts'] >= F.lit('2018-06-27 00:00:00'))
...           & (df['ts'] < F.lit('2018-06-29 00:00:00'))).show()
+---+-------------------+
| id|                 ts|
+---+-------------------+
|  2|2018-06-27 00:00:00|
|  3|2018-06-28 00:00:00|
+---+-------------------+

最后,您实际上并不需要lit函数。所以你可以只使用字符串:

>>> df.filter((df['ts'] >= '2018-06-27 00:00:00')
...           & (df['ts'] < '2018-06-29 00:00:00')).show()
+---+-------------------+
| id|                 ts|
+---+-------------------+
|  2|2018-06-27 00:00:00|
|  3|2018-06-28 00:00:00|
+---+-------------------+

对于时区,您可以查看from_unixtime function的pyspark文档。 我还粘贴了以下示例,以方便参考:

>>> spark.conf.set("spark.sql.session.timeZone", "America/Los_Angeles")
>>> time_df = spark.createDataFrame([(1428476400,)], ['unix_time'])
>>> time_df.select(from_unixtime('unix_time').alias('ts')).collect()
[Row(ts='2015-04-08 00:00:00')]
>>> spark.conf.unset("spark.sql.session.timeZone")