【发布时间】:2018-04-27 20:30:23
【问题描述】:
我正在开发一个返回元素数组的 UDAF。
每次更新的输入是索引和值的元组。
UDAF 所做的是将同一索引下的所有值相加。
例子:
对于输入(索引,值):(2,1), (3,1), (2,3)
应该返回 (0,0,4,1,...,0)
逻辑工作正常,但 update 方法 有问题,我的实现只为每行更新 1 个单元格,但该方法中的最后一个分配实际上复制整个数组 - 这是多余的并且非常耗时。
仅此一项任务就占了我的查询执行时间的 98%。
我的问题是,我怎样才能减少这个时间?是否可以在缓冲区数组中分配 1 个值而不必替换整个缓冲区?
P.S.:我正在使用 Spark 1.6,我无法很快升级它,所以请坚持使用适用于该版本的解决方案。
class SumArrayAtIndexUDAF() extends UserDefinedAggregateFunction{
val bucketSize = 1000
def inputSchema: StructType = StructType(StructField("index",LongType) :: StructField("value",LongType) :: Nil)
def dataType: DataType = ArrayType(LongType)
def deterministic: Boolean = true
def bufferSchema: StructType = {
StructType(
StructField("buckets", ArrayType(LongType)) :: Nil
)
}
override def initialize(buffer: MutableAggregationBuffer): Unit = {
buffer(0) = new Array[Long](bucketSize)
}
override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
val index = input.getLong(0)
val value = input.getLong(1)
val arr = buffer.getAs[mutable.WrappedArray[Long]](0)
buffer(0) = arr // TODO THIS TAKES WAYYYYY TOO LONG - it actually copies the entire array for every call to this method (which essentially updates only 1 cell)
}
override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
val arr1 = buffer1.getAs[mutable.WrappedArray[Long]](0)
val arr2 = buffer2.getAs[mutable.WrappedArray[Long]](0)
for(i <- arr1.indices){
arr1.update(i, arr1(i) + arr2(i))
}
buffer1(0) = arr1
}
override def evaluate(buffer: Row): Any = {
buffer.getAs[mutable.WrappedArray[Long]](0)
}
}
【问题讨论】:
-
到目前为止,我找到了this link,这可能有助于解释更多事情。我希望有更好的解决方案。
标签: scala performance apache-spark apache-spark-sql user-defined-functions