繁体   English   中英

PySpark Window Function Null处理

[英]PySpark Window Function Null handling

我正在尝试使用 pyspark==3.2.0 中的 window function 处理 null 值。

csv格式的原始数据为:

key1,key2,client_id,event_timestamp
1D7B****-****-****-****-******EC1E09,,9397****-****-****-****-******BFACBB,2021-02-25T16:04:12.391Z
1D7B****-****-****-****-******EC1E09,AE8D****-****-****-****-******3E7E75,9397****-****-****-****-******BFACBB,2021-02-25T02:15:44.587Z
1D7B****-****-****-****-******EC1E09,,9397****-****-****-****-******BFACBB,2021-02-25T02:19:59.084Z
1D7B****-****-****-****-******EC1E09,,9397****-****-****-****-******BFACBB,2021-02-25T02:31:07.170Z

我必须根据key1event_timestamp获取最后一个key2client_id 我写的当前 pyspark 代码是:

import pyspark.sql.functions as F
from pyspark.sql import SparkSession
from pyspark.sql.window import Window

sc = SparkSession
    .builder
    .appName("test run")
    .getOrCreate()

df = sc.read.csv('my-csv.csv')

df.select(
    F.col('key1'),
    F.last('key2', False).over(
        Window.partitionBy('key1').orderBy(F.col('event_timestamp').desc())
    ).alias('last_key2'),
    F.last('client_id', False).over(
        Window.partitionBy('key1').orderBy(F.col('event_timestamp').desc())
    ).alias('last_client_id')
)

但结果返回 2 行数据 - key2的一行是 null,而key2的一行是非空的。

key1,last_key2,last_client_id
1D7B****-****-****-****-******EC1E09,null,9397****-****-****-****-******BFACBB
1D7B****-****-****-****-******EC1E09,AE8D****-****-****-****-******3E7E75,9397****-****-****-****-******BFACBB

预期的结果在这里,因为如果我们仔细看的话, last_key2是 null。

key1,last_key2,last_client_id
1D7B****-****-****-****-******EC1E09,null,9397****-****-****-****-******BFACBB

如果我使用 window function 按key1分区,为什么 Spark 返回 2 行? 如何编写代码以便获得预期的结果?

您正在descending订购 Window 但使用last function 这就是您获得key2非空值的原因。 last function 根据您的订购为您提供 window 框架中的最后一个值。 您要在这里使用的是first function 或将顺序更改为ascending

from pyspark.sql import Window
import pyspark.sql.functions as F

w = Window.partitionBy('key1').orderBy(F.col('event_timestamp').desc())

df.select(
    F.col('key1'),
    F.first('key2', ignorenulls=False).over(w).alias('last_key2'),
    F.first('client_id', ignorenulls=False).over(w).alias('last_client_id')
).show(truncate=False)

请注意,像这样使用 Window 将始终为每个key1返回多行,因为没有分组依据或过滤。 您需要在 select 之后添加distinct()


话虽如此,对于这种情况,您可以简单地在您定义的相同 window 规范上使用row_number ,然后将列key2client_id分别重命名为last_key2last_client_id

df.withColumn(
    "rn",
    F.row_number().over(Window.partitionBy('key1').orderBy(F.col('event_timestamp').desc()))
).filter("rn = 1").select(
    F.col('key1'),
    F.col('key2').alias("last_key2"),
    F.col('client_id').alias("last_client_id")
).show(truncate=False)

#+------------------------------------+---------+------------------------------------+
#|key1                                |last_key2|last_client_id                      |
#+------------------------------------+---------+------------------------------------+
#|1D7B****-****-****-****-******EC1E09|null     |9397****-****-****-****-******BFACBB|
#+------------------------------------+---------+------------------------------------+

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM