1. spark sdf和pandas pdf相互转化
一般spark sdf转化为pandas pdf使用sdf.toPandas()
, pdf转化为sdf使用spark.createDataFrame(pdf)
,但是直接转化中间的序列化和反序列化耗时很长,所以在执行转化的时候使用apache arrow进行加速
pyarrow版本 >= 0.8.0
spark-defaults.conf文件添加:
spark.sql.execution.arrow.enabled true
或者在设置spark conf时设置:
conf = SparkConf().setAppName("Test").setMaster("local[*]")
conf.set("spark.sql.execution.arrow.enabled", True)
别人的对比:
execution.arrow.enabled | pdf -> sdf | sdf -> pdf |
---|---|---|
false | 4980ms | 722ms |
true | 72ms | 79ms |
tips: 尽管转化速度提高了,但pdf是单核运算,并没有用到分布式处理,所以最好不要处理大数据量。
当计算不适用于用arrow优化的时候可以自动退回非arrow优化的方式,这是配置参数为spark.sql.execution.arrow.fallback.enabled
每批进行向量化计算的数据量由spark.sql.execution.arrow.maxRecordsPerBatch
参数控制,默认10000条
2. sdf构建自定义函数时优先使用pandas_udf而不是udf
pandas udf建立在Apache arrow之上,带来了低开销, 高性能的udf,并且使用了pandas的向量化操作;而spark的udf是对每一条数据进行操作,这样就带来了性能的问题。但是pandas udf有一些数据类型不支持,例如:BinaryType,MapType, TimestampType 和嵌套的 StructType。
注意:有些低级的pyarrow版本在使用pandas_udf时会出错,因此最好使用比较高一点的版本
下面所有代码运行于linux系统中,python3.5包:numpy (1.17.0),pandas (0.25.2),pyarrow (0.13.0)
from pyspark import SparkConf
from pyspark.sql import SparkSession, Row
from pyspark.sql.functions import pandas_udf, PandasUDFType
import pyspark.sql.functions as F
from pyspark.sql.types import StringType
conf = SparkConf().setAppName("test").setMaster("local")
spark = SparkSession.builder.config(conf=conf).getOrCreate()
SCALAR
one or more pandas.Series -> one pandas.Series, 长度必须和原来的一致,2.4.3不支持MapType和StructType.
与dataframe.withColumn或dataframe.select一起使用
df = spark.createDataFrame([(1, 'goods'), (1, 'good'), (1, 'god'), (2, 'thanks'), (2, 'thank')], schema=['x', 'y'])
# to upper strings
@pandas_udf(StringType(), PandasUDFType.SCALAR)
def to_upper(s):
return s.str.upper()
df.select(df.x, to_upper(df.y)).show() # 1
df = spark.createDataFrame([[1, 2, 4], [-1, 2, 2]], ['a', 'b', 'c'])
# input multi-pandas.Series, pay attention to the returnType
@pandas_udf('double', PandasUDFType.SCALAR)
def fun_function(a, b, c