将pyspark中的UDF提升6倍

本文亮点

      调用jar中的UDF,减少python与JVM的交互,简单banchmark下对于54亿条数据集进行udf计算,从3小时的执行时间缩短至16分钟。
牺牲UDF部分的开发时间,尽量提高性能。
以接近纯python的开发成本,获得逼近纯scala的性能。兼顾性能和开发效率。

前提

       当遇到sql无法直接处理的数据时(比如加密解密、thrift解析操作二进制),我们需要自定义函数(UDF)来进行处理。出于开发效率的考虑,我们一般会选择airflow,使用pyspark脚本。

优化后的代码

from datetime import datetime
from pyspark.sql import SparkSession
import sys

if __name__ == "__main__":
    # 创建 Spark 会话
    spark = SparkSession.builder.appName("xxx").enableHiveSupport().getOrCreate()

    DT = sys.argv[1]
    HOUR = sys.argv[2]
    F_DT = datetime.strptime(DT, "%Y-%m-%d").strftime("%Y%m%d")
    tmp_tbl_name = f"""temp_xxx_pre_0_{F_DT}_{HOUR}"""

    print('''注册java函数''')
    spark.udf.registerJavaFunction("get_area_complex_value", "com.xxx.utf.block.AreaComplexValue")
    spark.udf.registerJavaFunction("most_common_element", "com.xxx.utf.common.MosCommonElement")
    spark.sql('''set hive.exec.dynamic.partition.mode=nonstrict;''')
    exec_sql = '''
  insert overwrite table xxx.xxx --你的目标表
			select
			a.distinct_id device_id -- l临时
			,app_id
			,install_datetime
			,os
			,ip
			,country
			,city
			,uuid
			,a.distinct_id
			,event_name
			,event_timestamp
			,event_datetime
			,game_id
			,game_type
			,round_id
			,travel_id
			,travel_lv
			,matrix
			,position
			,concat('[', concat_ws(',', clean), ']') as clean
			,block_id
			,index_id
			,rec_strategy
			,rec_strategy_fact
			,combo_cnt
			,gain_score
			,gain_item
			,block_list
			,lag_event_timestamp
			,(event_timestamp - lag_event_timestamp) / 1000 AS time_diff_in_seconds
			,most_common_element( replace( replace(replace(rec_strategy_fact, '[', ''), ']', ''), '"', '' )) as rec_strategy_fact_most
			,lag_matrix
			,is_clear_screen
			,is_blast
			,blast_row_col_cnt
			,CASE 
                WHEN size(clean) > 0 THEN
                    CASE 
                        WHEN (IF(size(lag_clean_3) > 0, 1, 0) + IF(size(lag_clean_2) > 0, 1, 0) 
### PySparkJava 集成及其使用 #### 使用 Maven 构建支持 Hive 的 Spark 为了使 PySpark 支持测试功能并兼容 Hive,构建过程需通过特定命令完成。对于想要运行 PySpark 测试的情况,应当执行如下指令来编译带有 Hive 功能的 Spark版本[^1]: ```bash ./build/mvn -DskipTests clean package -Phive ./python/run-tests ``` #### PySparkJava 的集成方式 尽管 PySpark 主要用于 Python 编程环境,但其底层依赖于 JVM(Java 虚拟机),因此可以实现与 Java 应用程序的良好交互。 ##### 方法一:调用 PySpark API 进行数据处理 可以直接利用 PySpark 提供的功能,在 Python 中编写逻辑并通过 Py4J 实现跨语言操作。这种方式下开发人员可以在熟悉的 Python 生态内工作,同时享受 Scala/Java 社区维护的核心库带来的性能优势。 ##### 方法二:创建自定义 UDF (User Defined Functions) 如果业务需求涉及到复杂算法或者已有成熟的 Java 类库,则可以通过注册用户定义函数的方式将这些资源引入到 PySpark 工作流当中。具体做法是在 Java 或者 Scala 中定义所需的方法,并将其转换为可用于 DataFrame 操作的形式: ```java // Example of a simple UDF written in Java that can be used within PySpark. import org.apache.spark.sql.api.java.UDF1; public class MyCustomFunction implements UDF1<String, String> { @Override public String call(String input) throws Exception { return "Processed_" + input; } } ``` 接着在 Python 环境里加载此 JAR 文件并将上述类实例化为可调用对象: ```python from pyspark.sql import SparkSession spark = SparkSession.builder \ .appName("PythonUDFExample")\ .getOrCreate() # Register the custom function as an SQL function named 'my_func' spark.udf.register("my_func", lambda s: ..., StringType()) df = spark.createDataFrame([("data point 1",), ("data point 2",)], ["col"]) result_df = df.selectExpr("my_func(col)") result_df.show() ``` 请注意实际应用时需要替换 `lambda` 表达式部分为指向已打包好的 jar 包中的完整路径以及相应类型的返回值声明。 #### 性能优化建议 针对内存计算优化方面,无论是离线还是在线场景都强调了基准测试的重要性。合理配置参数能够显著提升应用程序效率,尤其是在大规模分布式环境中更是如此[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值