Apache spark 如何停止在条件语句中解析UDF列
我想执行一些条件分支以避免计算不必要的节点,但我注意到,如果condition语句中的source列是一个UDF,那么否则将被解析,不管:Apache spark 如何停止在条件语句中解析UDF列,apache-spark,pyspark,apache-spark-sql,Apache Spark,Pyspark,Apache Spark Sql,我想执行一些条件分支以避免计算不必要的节点,但我注意到,如果condition语句中的source列是一个UDF,那么否则将被解析,不管: @pandas_udf("double", PandasUDFType.SCALAR) def udf_that_throws_exception(*cols): raise Exception('Error') @pandas_udf("int", PandasUDFType.SCALAR) def simple_mul_udf(*cols
@pandas_udf("double", PandasUDFType.SCALAR)
def udf_that_throws_exception(*cols):
raise Exception('Error')
@pandas_udf("int", PandasUDFType.SCALAR)
def simple_mul_udf(*cols):
result = cols[0]
for c in cols[1:]:
result *= c
return result
df = spark.range(0,5)
df = df.withColumn('A', lit(1))
df = df.withColumn('B', lit(2))
df = df.withColumn('udf', simple_mul('A','B'))
df = df.withColumn('sql', expr('A*B'))
df = df.withColumn('res', when(df.sql < 100, lit(1)).otherwise(udf_that_throws(lit(0))))
df = df.withColumn('cond', when(df.udf < 100, lit(1)).otherwise(lit(0)))
df = df.withColumn('res', when(df.cond == lit(1), lit(1)).otherwise(udf_that_throws_exception(lit(0))))
@pandas\u udf(“double”,PandasUDFType.SCALAR)
抛出异常(*cols)的def udf_:
引发异常('错误')
@pandas_udf(“int”,PandasUDFType.SCALAR)
定义简单多个自定义项(*cols):
结果=cols[0]
对于cols[1:]中的c:
结果*=c
返回结果
df=火花范围(0,5)
df=df.带柱('A',发光(1))
df=带柱的df('B',发光(2))
df=df.withColumn('udf',simple_mul('A','B'))
df=df.withColumn('sql',expr('A*B'))
df=df.withColumn('res',当(df.sql<100,lit(1))。否则(udf_抛出(lit(0)))
上述代码按预期工作,本例中的语句始终为true,因此不会调用引发异常的我的UDF
但是,如果我将条件改为使用df.udf,则会突然调用否则的udf,即使条件结果没有更改,我也会得到异常
我想我可以通过从条件中删除UDF来混淆它,但是不管怎样,都会出现相同的结果:
@pandas_udf("double", PandasUDFType.SCALAR)
def udf_that_throws_exception(*cols):
raise Exception('Error')
@pandas_udf("int", PandasUDFType.SCALAR)
def simple_mul_udf(*cols):
result = cols[0]
for c in cols[1:]:
result *= c
return result
df = spark.range(0,5)
df = df.withColumn('A', lit(1))
df = df.withColumn('B', lit(2))
df = df.withColumn('udf', simple_mul('A','B'))
df = df.withColumn('sql', expr('A*B'))
df = df.withColumn('res', when(df.sql < 100, lit(1)).otherwise(udf_that_throws(lit(0))))
df = df.withColumn('cond', when(df.udf < 100, lit(1)).otherwise(lit(0)))
df = df.withColumn('res', when(df.cond == lit(1), lit(1)).otherwise(udf_that_throws_exception(lit(0))))
df=df.withColumn('cond',当(df.udf<100,lit(1))。否则(lit(0)))
df=df.withColumn('res',when(df.cond==lit(1),lit(1))。否则(引发异常的udf(lit(0)))
我想这与Spark优化的方式有关,这很好,但我正在寻找任何不产生成本的方法来实现这一点。有什么想法吗
编辑
请按要求提供更多信息。我们正在编写一个可以接受任意模型的处理引擎,代码生成图形。在此过程中,我们会根据运行时的值状态做出决策。我们大量使用熊猫UDF。因此,想象一下这样一种情况:图形中有多条路径,并且根据运行时的某些条件,我们希望遵循其中一条路径,而不触及其他所有路径
我想将这个逻辑编码到图中,这样就不需要在代码中收集和分支
我提供的示例代码仅用于演示目的。我所面临的问题是,如果if语句中使用的列是一个UDF,或者,如果它似乎是从一个UDF派生出来的,那么即使它从未实际使用过,否则条件也总是被执行。如果If/ELSE是廉价的操作,例如文字,我不介意,但是如果列UDF(可能在两侧)导致一个大的聚合或其他实际上刚刚丢弃的长度过程,该怎么办?在PySpark中,UDF是预先计算的,因此您得到的是次优的行为。您也可以从查询计划中看到它:
== Physical Plan ==
*(2) Project [id#753L, 1 AS A#755, 2 AS B#758, pythonUDF1#776 AS udf#763, CASE WHEN (pythonUDF1#776 < 100) THEN 1.0 ELSE pythonUDF2#777 END AS res#769]
+- ArrowEvalPython [simple_mul_udf(1, 2), simple_mul_udf(1, 2), udf_that_throws_exception(0)], [id#753L, pythonUDF0#775, pythonUDF1#776, pythonUDF2#777]
+- *(1) Range (0, 5, step=1, splits=8)
你能解释清楚你的问题吗..你在使用df.udf时遇到了什么问题?请同时添加udf的逻辑