我正在玩Scala中为Hive编写Generic UDF。我的第一个测试是编写一个函数来求和数组(复杂数据类型)。
我的代码存根看起来像这样(因为这是一个存根,请忽略asInstanceOf
的用法:D):
...
class SumElements extends GenericUDF {
protected val expectedCategories: Array[Category] = Array(ObjectInspector.Category.LIST)
protected var listInspector: ListObjectInspector = _
@throws(classOf[UDFNullArgumentException])
@throws(classOf[UDFArgumentLengthException])
@throws(classOf[UDFArgumentTypeException])
override def initialize(inspectors: Array[ObjectInspector]): ObjectInspector = {
...
listInspector = inspectors(0).asInstanceOf[ListObjectInspector]
...
}
@throws(classOf[HiveException])
override def evaluate(args: Array[DeferredObject]): AnyRef = {
val list: util.List[_] = listInspector.getList(args(0).get)
val listLength: Int = listInspector.getListLength(list)
val tmp: IndexedSeq[Int] = for {
i <- 0 until listLength
} yield listInspector.getListElement(list, i).asInstanceOf[IntWritable].get
tmp.sum.asInstanceOf[AnyRef]
}
override def getDisplayString(args: Array[String]): String = "SumElements(Array<Numeric>)"
}
基本上,我必须阅读列表的每个元素,将其转换为IntWritable
,然后get
原语。上面的代码工作并返回正确的总和,但不是通用的:它只适用于Int
。
尝试创建一个通用的我得到了这个:
class HadoopList(list: util.List[_], listInspector: ListObjectInspector) {
def fromWritableToPrimitive[W <: Writable, N]: IndexedSeq[N] = {
val listLength: Int = listInspector.getListLength(list)
val tmp: IndexedSeq[N] = for {
i <- 0 until listLength
} yield listInspector.getListElement(list, i).asInstanceOf[W].get.asInstanceOf[N]
tmp
}
}
但结果是Writable
接口没有强制执行函数get
!发现具体的Writable类型不能保证具有get
方法,这是非常令人惊讶的。
我的问题是:
get
,以便我可以一般使用?答案 0 :(得分:0)
虽然不是用Scala编写的,但是查看hive本身的泛型UDAF,例如GenericUDAFAverage或GenericUDAFHistogramNumeric,它们似乎将任何原始数字输入转换为Double(使用PrimitiveObjectInspectorUtils.getDouble)然后操作双打。
另一个选择是在运行时找到类型(通过针对每个数字基元类型检查isInstanceOf)然后调用泛型函数。