PySpark: фильтрация фрейма данных по полю даты в диапазоне, где дата-строка

мои фреймы данных содержат одно поле, которое является датой, и оно отображается в строковом формате, например

'2015-07-02T11:22:21.050Z'

мне нужно отфильтровать фрейм данных на дату, чтобы получить только записи за последнюю неделю. Итак, я пробовал подход карты, где я преобразовал строковые даты в объекты datetime с помощью strptime:

def map_to_datetime(row):
     format_string = '%Y-%m-%dT%H:%M:%S.%fZ'
     row.date = datetime.strptime(row.date, format_string)

df = df.map(map_to_datetime)

и тогда я бы применил фильтр как

df.filter(lambda row:
    row.date >= (datetime.today() - timedelta(days=7)))

мне удается заставить отображение работать, но фильтр не работает с

TypeError: условие должно быть строкой или столбцом

есть ли способ использовать фильтрацию таким образом, который работает или я должен изменить подход и как?

2 ответов


вы можете решить эту проблему без использования кода Python рабочей стороны и переключения на RDDs. Прежде всего, поскольку вы используете строку ISO 8601, ваши данные могут быть непосредственно отлиты на дату или метку времени:

from pyspark.sql.functions import col

df = sc.parallelize([
    ('2015-07-02T11:22:21.050Z', ),
    ('2016-03-20T21:00:00.000Z', )
]).toDF(("d_str", ))

df_casted = df.select("*",
    col("d_str").cast("date").alias("dt"), 
    col("d_str").cast("timestamp").alias("ts"))

это сэкономит один раунд между JVM и Python. Есть также несколько способов, которыми вы можете подойти ко второй части. Только дата:

from pyspark.sql.functions import current_date, datediff, unix_timestamp

df_casted.where(datediff(current_date(), col("dt")) < 7)

метки:

def days(i: int) -> int:
    return 60 * 60 * 24 * i

df_casted.where(unix_timestamp() - col("ts").cast("long") < days(7))

вы также можете посмотреть current_timestamp и date_sub

Примечание: I избегайте использования DataFrame.map. Лучше использовать . Это сэкономит вам некоторую работу при переключении на 2.0+


Я понял, как решить мою проблему, используя SparkSQL API с датами, хранящимися в виде строк, и делая это:

last_week = (datetime.today() - timedelta(days=7)).strftime(format='%Y-%m-%d')

new_df = df.where(df.date >= last_week)