[英]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
我必须根据key1
和event_timestamp
获取最后一个key2
和client_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
,然后将列key2
和client_id
分别重命名为last_key2
和last_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.