pyspark的“介于”功能:不包括时间戳的范围搜索

Vin*_*lar 6 python datetime range between pyspark

pyspark的“介于”功能不包含在时间戳输入中。

例如,如果我们想要两个日期之间的所有行,例如“ 2017-04-13”和“ 2017-04-14”,那么当日期作为字符串传递时,它将执行“排他”搜索。即,它省略了“ 2017-04-14 00:00:00”字段

但是,该文档似乎暗示它具有包容性(尽管在时间戳上没有引用)

当然,一种方法是从上限添加一个微秒,并将其传递给函数。但是,不是一个很好的解决方案。进行包含式搜索的任何干净方法?

例:

import pandas as pd
from pyspark.sql import functions as F
... sql_context creation ...
test_pd=pd.DataFrame([{"start":'2017-04-13 12:00:00', "value":1.0},{"start":'2017-04-14 00:00:00', "value":1.1}])
test_df = sql_context.createDataFrame(test_pd).withColumn("start", F.col("start").cast('timestamp'))
test_df.show()

+--------------------+-----+
|               start|value|
+--------------------+-----+
|2017-04-13 12:00:...|  1.0|
|2017-04-14 00:00:...|  1.1|
+--------------------+-----+

test_df.filter(F.col("start").between('2017-04-13','2017-04-14')).show()

+--------------------+-----+
|               start|value|
+--------------------+-----+
|2017-04-13 12:00:...|  1.0|
+--------------------+-----+
Run Code Online (Sandbox Code Playgroud)

Vin*_*lar 17

找到了答案。pyspark 的“介于”函数在处理时间戳输入时不一致。

  1. 如果您在没有时间的情况下以字符串格式提供输入,它将执行排他搜索(不是我们从上面链接的文档中期望的)。
  2. 如果您将输入作为日期时间对象或精确时间(例如,“2017-04-14 00:00:00”)提供,则它会执行包含搜索。

对于上面的例子,这里是独占搜索的输出(使用 pd.to_datetime):

test_df.filter(F.col("start").between(pd.to_datetime('2017-04-13'),pd.to_datetime('2017-04-14'))).show()

+--------------------+-----+
|               start|value|
+--------------------+-----+
|2017-04-13 12:00:...|  1.0|
|2017-04-14 00:00:...|  1.1|
+--------------------+-----+
Run Code Online (Sandbox Code Playgroud)

同样,如果我们以字符串格式提供日期和时间,它似乎执行了包含搜索:

test_df.filter(F.col("start").between('2017-04-13 12:00:00','2017-04-14 00:00:00')).show()

+--------------------+-----+
|               start|value|
+--------------------+-----+
|2017-04-13 12:00:...|  1.0|
|2017-04-14 00:00:...|  1.1|
+--------------------+-----+
Run Code Online (Sandbox Code Playgroud)

  • @VinayKolar [之间() 函数的源代码](https://github.com/apache/spark/blob/v2.3.0/python/pyspark/sql/column.py#L551) 似乎表明这是一个包容性搜索 (2认同)

Ann*_* K. 6

.between() 方法总是包含在内。您示例中的问题是,当您将字符串传递给 .between() 方法时,它也会将您的数据视为字符串。对于字符串比较, '2017-04-14 00:00:00' 严格大于 '2017-04-14' 因为前者的字符串比后者长,这就是为什么在您的示例中过滤掉第二个日期的原因. 为避免“不一致”,您应该将日期时间格式的参数传递给 .between() ,如下所示:

filtered_df = (test_df.filter(F.col("start")
                .between(dt.strptime('2017-04-13 12:00:00', '%Y-%m-%d %H:%M:%S'), 
                         dt.strptime('2017-04-14 00:00:00', '%Y-%m-%d %H:%M:%S'))))
Run Code Online (Sandbox Code Playgroud)

这将产生预期的结果:

+--------------------+-----+
|               start|value|
+--------------------+-----+
|2017-04-13 12:00:...|  1.0|
|2017-04-14 00:00:...|  1.1|
+--------------------+-----+
Run Code Online (Sandbox Code Playgroud)