Scala和Hive:编写适用于所有类型Writable的泛型方法的最佳方法

时间:2016-10-22 20:05:43

标签: scala hadoop generics hive

我正在玩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方法,这是非常令人惊讶的。

我的问题是:

  1. 我错过了什么吗?是否有一个IntWritable的超类提供合约get,以便我可以一般使用?
  2. 为什么Java似乎会自动将IntWritable转换为Int而Scala不会? Java示例没有投射步骤
  3. 有更好的Scala方法吗?

1 个答案:

答案 0 :(得分:0)

虽然不是用Scala编写的,但是查看hive本身的泛型UDAF,例如GenericUDAFAverageGenericUDAFHistogramNumeric,它们似乎将任何原始数字输入转换为Double(使用PrimitiveObjectInspectorUtils.getDouble)然后操作双打。

另一个选择是在运行时找到类型(通过针对每个数字基元类型检查isInstanceOf)然后调用泛型函数。