基于日期过滤Spark DataFrame

61

我有一个数据框

date, string, string

我想选择某个时间段之前的日期。我尝试了以下方法,但没有成功。
 data.filter(data("date") < new java.sql.Date(format.parse("2015-03-14").getTime))

我收到了以下错误提示

org.apache.spark.sql.AnalysisException: resolved attribute(s) date#75 missing from date#72,uid#73,iid#74 in operator !Filter (date#75 < 16508);

我猜测查询语句不正确。有人能展示一下查询语句应该如何格式化吗?

我检查了数据框中的所有条目都有值 - 它们确实有。

7个回答

85
以下解决方案适用于Spark 1.5及以上版本:
对于低于此版本的:
// filter data where the date is lesser than 2015-03-14
data.filter(data("date").lt(lit("2015-03-14")))      

大于的符号:

// filter data where the date is greater than 2015-03-14
data.filter(data("date").gt(lit("2015-03-14"))) 

为了判断相等性,你可以使用equalTo===

data.filter(data("date") === lit("2015-03-14"))

如果您的DataFrame日期列是StringType类型的,可以使用to_date函数进行转换。
// filter data where the date is greater than 2015-03-14
data.filter(to_date(data("date")).gt(lit("2015-03-14"))) 

您还可以使用 year 函数按年份进行筛选:

// filter data where year is greater or equal to 2016
data.filter(year($"date").geq(lit(2016))) 

1
在Spark中,是否有像“between”一样的选项适用于日期列?另外,我的日期格式为“dd/MM/yyyy”。 - Sivailango
@Sivailango 当然,它是在between上进行过滤的,请查看我的答案这里 - eliasah
df.select(df("ID"), date_format(df("Week_Ending_Date"), "yyyy-MM-dd")) .filter(date_format(df("Week_Ending_Date"), "yyyy-MM-dd").between("2015-07-05", "2015-09-02"))。这样对吗?另外,我在这里看到了你的另一个答案:https://dev59.com/2ZHea4cB1Zd3GeqPpnvP - Sivailango
我们能在时间戳列中找到空值吗? - Darshan
如果您找不到lit,请查看pyspark.sql.functions - ijoseph
显示剩余3条评论

24

不要像其他答案建议的那样使用此方法

.filter(f.col("dateColumn") < f.lit('2017-11-01'))

但是使用这个替代

.filter(f.col("dateColumn") < f.unix_timestamp(f.lit('2017-11-01 00:00:00')).cast('timestamp'))

这将使用 TimestampType 而不是 StringType,在某些情况下会更加高效。例如,Parquet谓词下推仅适用于后者。

编辑: 两个片段都假定导入了以下内容:

from pyspark.sql import functions as f

1
f是什么?另外,请分享导入内容。 - Jus12
好的,我已经将它们添加到答案中了。 - Ruurtjan Pul

19

我认为最易读的表达方式是使用SQL语句:

df.filter("my_date < date'2015-01-01'")

我们可以通过查看.explain()的物理计划来验证其正确性。

+- *(1) Filter (isnotnull(my_date#22) && (my_date#22 < 16436))

1
这对我没有用,但是.filter("effectivedate > to_date('1900-02-02')") 对我有用(与我的情况相关)。很可能我需要加载某个库才能使给定的解决方案起作用。总的来说,这是最好的答案。 - Harlan Nelson
奇怪 - 它应该在原始的Pyspark中运行。 - RobinL

9
在PySpark(Python)中,其中一个选项是将列设置为unix_timestamp格式。我们可以将字符串转换为unix_timestamp,并指定格式,如下所示。 注意,我们需要导入unix_timestamp和lit函数。
from pyspark.sql.functions import unix_timestamp, lit

df.withColumn("tx_date", to_date(unix_timestamp(df_cast["date"], "MM/dd/yyyy").cast("timestamp")))

现在我们可以应用过滤器。
df_cast.filter(df_cast["tx_date"] >= lit('2017-01-01')) \
       .filter(df_cast["tx_date"] <= lit('2017-01-31')).show()

4
df=df.filter(df["columnname"]>='2020-01-13')

我认为可以简单地这样做: df[df["columnname"] >= '2020-01-13'] - travelingbones

1
我们还可以在筛选器中使用类似SQL的表达式:
注意 -> 这里我展示了两个条件和一个未来的日期范围以供参考:
ordersDf.filter("order_status = 'PENDING_PAYMENT' AND order_date BETWEEN '2013-07-01' AND '2013-07-31' ")

0

我的看法是应该这样:

import java.util.Date
import java.util.Calendar
import java.sql.Timestamp
import java.sql.Date

val jDate = Calendar.getInstance().getTime()
val sqlDateTime = new java.sql.Timestamp(jDate.getTime())
val sqlDate = new java.sql.Date(jDate.getTime())

data.filter(data("date").gt(sqlDate)) 
data.filter(data("date").gt(sqlDateTime))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接