基于pandas实现UDF函数

687 阅读2分钟

「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战

pandas UDF

pandas UDF 是用户定义的函数, 由spark来执行, 使用arrow传输数据, pandas函数处理数据(写的py函数),允许向量化(充分的利用计算机的并行性)操作 , pandas UDF 是使用 pandas_udf() 作为装饰器(相当于给pandas 函数扩充功能, 支持将其转换为spark 的函数)来定义的, 不需要额外配置, 而且 pandas_udf() 通过作为 pyspark的函数API使用(F.pandas_udf())

  • 基于pandas实现UDF函数: series To series

    • 类型可以表现为: pandas.series TO pandas .series

需求: 计算两列的乘积

from pyspark import SparkContext, SparkConf
from pyspark.sql import SparkSession
from pyspark.sql.types import *
import  pandas as pd
import pyspark.sql.functions as F
import os

# 目的: 锁定远端操作环境, 避免存在多个版本环境的问题
os.environ["SPARK_HOME"] = "/export/server/spark"
os.environ["PYSPARK_PYTHON"] = "/root/anaconda3/bin/python"
os.environ["PYSPARK_DRIVER_PYTHON"] = "/root/anaconda3/bin/python"

if __name__ == '__main__':
    print("基于pandas 实现 pyspark的 UDF函数定义与使用")

    # 1) 创建sparkSession对象
    spark = SparkSession.builder.master("local[*]").appName("_02_pd_udf").getOrCreate()

    # 开启 arrow方案:
    spark.conf.set("spark.sql.execution.arrow.pyspark.enabled", True)

    # 2) 初始一份数据集
    df = spark.createDataFrame([(1, 3), (2, 4), (1, 2), (3, 3)], ['a', 'b'])

    df.createTempView("t1")

    # 3) 定义一个接收两列的数据, 返回乘积结果的pandas 函数
    def cj_func(a:pd.Series,b:pd.Series) -> pd.Series:
        return  a * b

    # 4) 将这个pandas的函数 转换为spark SQL的函数:  pandas_udf()
    
    # 方式一: 通过原生方式来注册 pandas 的函数
    cj_dsl_pdf = spark.udf.register('cj_s_pdf', cj_func, returnType=LongType())

    # DSL:
    df.select(df['a'], df['b'], cj_dsl_pdf('a', 'b')).show()
    
    # sql:
    spark.sql("select a, b, cj_s_pdf(a,b)  from t1").show()
    
    # 方式二: 通过 API形式定义  进行注册
    pd_udf = F.pandas_udf(cj_func, returnType=LongType())

    # DSL中使用
    df.select(df['a'],df['b'],pd_udf('a','b')).show()

    # SQL中使用   方式一 无法在SQL中使用  报错
    # spark.sql("select a, b, pd_udf(a,b)  from t1").show()

    # 方式三: 基于注解(装饰器方案)
    @F.pandas_udf(returnType=LongType())
    def cj_func_2(a:pd.Series,b:pd.Series) -> pd.Series:
        return  a * b

    # DSL中使用
    df.select(df['a'], df['b'], cj_func_2('a', 'b')).show()

    # SQL中使用 无法使用的 
    #spark.sql("select a, b, cj_func_2(a,b)  from t1").show()