PySpark DataFrame如何实现支持多参数传入的UDF
PySpark多参数UDF传参实现数组字典过滤取值
问题场景
我有一个PySpark DataFrame,列值为数组类型,数组内每个元素都是字典结构,示例数据如下:
| class | product |
|---|---|
| {"deleteDate": null, "class":"AB", "validFrom": "2022-09-01", "validTo": "2009-08-31"}, {"deleteDate": null, "class":"CD", "validFrom": "2009-09-01", "validTo": "2024-08-31"} | {"deleteDate": "2021-09-01", "class":"AB", "validFrom": "2003-09-01", "validTo": "2009-03-01"}, {"deleteDate": null, "class":"CD", "validFrom": "2009-09-01", "validTo": "2024-08-31"} |
我需要按指定条件过滤数组内的元素,初始编写的处理代码如下:
def getelement(value,entity): list_url = [] for i in range(len(value)): if value[i] is not None and (value[i].deleteDate is None): if (value[i].validFrom <= (Date of Today)) & (value[i].validFrom >= (date of today)): list_url.append(value[i].entity) if list_url: return str(list_url[-1]) if not list_url: return None udfgeturl=F.udf(lambda z: getelement(z) if not z is None else "" , StringType() ) master = df.withColumn( 'ClassName', udfgeturl('Class'))
当前存在的问题:getelement函数设计需要接收两个入参,value对应传入的DataFrame列,entity对应需要提取结果的字典键名,但现有UDF仅支持传入单个参数调用getelement,无法满足双参数传入需求,需要调整UDF定义与传参方式实现多参数传入。
可行解决方案
调整要点
- PySpark UDF本身支持传入多个列作为参数,不需要用单参数lambda包装,注册UDF后调用时按顺序传入多个列/固定值即可
- 修复原代码的逻辑问题:
- 原日期判断存在笔误,重复判断
validFrom字段,实际生效逻辑应为validFrom <= 今日 且 validTo >= 今日 - 如果数组内元素是dict类型,不能用点
.取值,需要用[key]/get(key)方式访问,可兼容Row类型 - 补全缩进错误,统一空值处理逻辑
- 原日期判断存在笔误,重复判断
修正后完整代码
import pyspark.sql.functions as F from pyspark.sql.types import StringType from datetime import date # 取今日日期,格式和数据内yyyy-MM-dd格式对齐 today = date.today().isoformat() def getelement(value, entity): if not value: return None match_res = [] for item in value: # 跳过空元素、已标记删除的元素 if item is None or item.get("deleteDate") is not None: continue # 日期范围判断:筛选当前处于生效周期内的条目 if item.get("validFrom") <= today and item.get("validTo") >= today: match_res.append(item.get(entity)) # 返回最后一个匹配到的值,无匹配返回None return str(match_res[-1]) if match_res else None # 直接注册双参数UDF udfgeturl = F.udf(getelement, StringType()) # 调用时第一个参数传目标列,第二个参数传要提取的键名,同一UDF可复用到不同列 master = df.withColumn('ClassName', udfgeturl(F.col('class'), F.lit('class'))) \ .withColumn('ProductClass', udfgeturl(F.col('product'), F.lit('class')))
注:如果数组内元素是PySpark Row对象而非dict,把
item.get(key)改成item[key]即可,逻辑完全一致。如果需要提取的entity字段是固定值,也可以直接把字段名写在UDF逻辑里,不需要作为参数传入。
内容的提问来源于stack exchange,提问作者rooya sh
相关产品推荐
相关产品推荐

