pyspark中的重状态UDF

时间:2018-12-03 10:54:41

标签: python apache-spark pyspark user-defined-functions

我必须在Spark中将非常强大的python函数作为UDF运行,并且我想在UDF中缓存一些数据。此案类似于上述here

我知道它很慢而且是错误的。 但是现有的基础设施正在兴起,我不想为此建立新的基础设施并单独处理数据加载/并行化/故障安全。

这是我的spark程序的外观:

from mymodule import my_function # here is my function
from pyspark.sql.types import *
from pyspark.sql.functions import udf
from pyspark.sql.session import SparkSession

spark = SparkSession.builder.getOrCreate()

schema = StructType().add("input", "string")
df = spark.read.format("json").schema(schema).load("s3://input_path")

udf1 = udf(my_function, StructType().add("output", "string"))
df.withColumn("result", udf1(df.input)).write.json("s3://output_path/")

my_function在内部使用慢速构造函数调用对象的方法。 因此,我不想为每个条目都初始化该对象,而是尝试对其进行缓存:

from my_slow_class import SlowClass
from cachetools import cached

@cached(cache={}) 
def get_cached_object():
    # this call is really slow therefore I am trying 
    # to cache it with cachetools
    return SlowClass() 

def my_function(input):
    slow_object = get_cached_object()
    output = slow_object.call(input)
    return {'output': output}

mymodulemy_slow_class作为模块安装在每台火花机上。

似乎可行。该构造函数仅被调用几次(对于输入数据帧中的100k行,仅调用10-20次)。这就是我想要的。

我担心的是Spark执行程序内部的多线程/多处理,以及是否在许多并行的SlowObject调用之间共享了缓存的my_function实例。

我可以依靠这样一个事实,即my_function在辅助节点上的python进程中一次被调用一次吗? Spark是否在执行我的UDF的python进程中使用任何多处理/多线程处理?

1 个答案:

答案 0 :(得分:1)

Spark派生Python进程来创建单个工作程序,但是单个工作程序进程中的所有处理都是顺序的,除非UserDefinedFunction明确使用了多线程或多处理。

只要将状态用于缓存并且slow_object.call是一个纯函数,您就不必担心。