本文亮点
调用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)