我正在尝试进行需要自定义功能的高性能计算。
作为第一阶段,我试图分析使用UDF的效果,我得到了奇怪的结果。
基本上我使用带有50M记录的range选项创建一个数据帧并缓存它。
然后我做一个过滤器来找到小于10的那些并计算它们。一旦做了列< 10,一次通过UDF。
我每次动作10次以获得好时间估计。
我发现这两种方法大约在同一时间:约4秒。
我也在我拥有的一个内部集群中尝试过它(8个节点,使用yarn,每个节点有~40GB内存和大量内核)。第一个选项的结果是1秒,第二个选项的结果是8秒。
首先,我不明白在databricks集群中我是如何获得相同的性能的。 UDF不应该慢得多吗?毕竟,没有codegen所以我应该看到一个慢得多的过程。
其次我不明白这两个问题之间的巨大差异:在一个我几乎相同的时间和另一个x8差异。
最后,我试图弄清楚如何在本地编写自定义函数(即spark的方式)。我试着看一下spark的代码,然后出现了类似的东西:
import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.analysis.TypeCheckResult
import org.apache.spark.sql.catalyst.expressions.codegen.{CodegenContext, ExprCode}
import org.apache.spark.sql.catalyst.plans.logical.LogicalPlan
import org.apache.spark.sql.catalyst.util.TypeUtils
import org.apache.spark.sql.types._
import org.apache.spark.util.Utils
import org.apache.spark.sql.catalyst.expressions._
case class genf(child: Expression) extends UnaryExpression with Predicate with ImplicitCastInputTypes {
override def inputTypes: Seq[AbstractDataType] = Seq(IntegerType)
override def toString: String = s"$child < 10"
override def eval(input: InternalRow): Any = {
val value = child.eval(input)
if (value == null)
{
false
} else {
child.dataType match {
case IntegerType => value.asInstanceOf[Int] < 10
}
}
}
override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = {
defineCodeGen(ctx, ev, c => s"($c) < 10")
}
}
然而,这不起作用,因为它只能在sql包中起作用(例如,AbstractDataType是私有的)。
这个代码是否在正确的方向?我怎么能让它发挥作用?
感谢。