通过类型的大小写匹配,根据SparkSQL中的类型转换值

时间:2016-01-06 14:38:56

标签: scala apache-spark

是否可以匹配Scala中的参数类型?假设我有一个函数接收两个参数:valuetype。我想使用模式匹配来进行类型转换。

这样的事情:

datatype match {
  case IntegerType => return value.toInt
  case FloatType => return value.toFloat
  case StringType => return value
  case DecimalType(_,_) => return BigDecimal(value) // this is not working
  case _ => return strrepr
}

此处DecimalType接受两个参数来指定所需精度的精度。它可以是例如:

org.apache.spark.sql.types.DecimalType = DecimalType(10,2)

我尝试了几个选项,似乎没有任何工作:

  • 对于 case DecimalType => return BigDecimal(value) ,我得到:

    error: pattern type is incompatible with expected type;
       found   : org.apache.spark.sql.types.DecimalType.type
       required: org.apache.spark.sql.types.DataType
       Note: if you intended to match against the class, try `case DecimalType(_,_)`
    
  • 对于 case DecimalType(_,_) => return BigDecimal(value) ,我得到:

    error: result type Boolean of unapply defined in method unapply in object DecimalType does not conform to Option[_] or Boolean
    
  • 对于 case DecimalType[_,_] => return BigDecimal(value) ,我得到:

    error: org.apache.spark.sql.types.DecimalType does not take type parameters
    

3 个答案:

答案 0 :(得分:4)

问题是在代码中使用return。你说你在某个地方使用这个代码片段。该函数的返回类型是什么?显然,你打算有时它是Integer,有时是String,有时是BigDecimal;但是如果使用return,它将查看返回对象的类型以确定函数的返回类型。通常,您应该强烈避免在Scala代码中使用return。返回函数体中的最后一个求值。使用return的唯一情况是,您希望强制在函数体中的其他位置返回值。但是,更好的方法是将返回对象保存在变量中,并在函数体的最后一行评估该变量。永远不要使用退货!

没有return可行

scala> val datatype = DecimalType(10, 2)
datatype: org.apache.spark.sql.types.DecimalType = DecimalType(10,2)

scala> val value = BigDecimal(10)
value: scala.math.BigDecimal = 10

scala> datatype match {case DecimalType(_,_) => value}
res150: scala.math.BigDecimal = 10

**返回问题**

scala> def test = {datatype match {case DecimalType(_,_) => return value}}
<console>:138: error: method test has return statement; needs result type
       def test = {datatype match {case DecimalType(_,_) => return value}}

scala> def test:BigDecimal = {datatype match {case DecimalType(_,_) => return value}}
test: BigDecimal

scala> def test:DataType = {datatype match {case DecimalType(_,_) => return value}}
<console>:138: error: type mismatch;
 found   : scala.math.BigDecimal
 required: org.apache.spark.sql.types.DataType
       def test:DataType = {datatype match {case DecimalType(_,_) => return value}}

scala> def test3 = {datatype match {case DecimalType(_,_) => value}}
test3: scala.math.BigDecimal

答案 1 :(得分:4)

原来只有DecimalType模式与零参数匹配:

  case DecimalType() => ...

如果您需要精度和比例,您必须定义案例的类型并手动提取它们:

datatype match {
  case dt: DecimalType =>
    val precision = dt.precision
    val scale = dt.scale
    ...

答案 2 :(得分:0)

可能是我正在处理的代码所特有的,或者可能因SQL供应商而异,但是我发现DecimalType没有单一的基础类型。有时我会收到火花Decimal,而其他时候会收到Java BigDecimal。如果我尝试将getAs[Decimal]设为BigDecimal时遇到异常。如果我尝试将getAs[BigDecimal]设为Decimal,则会出现异常。

要解决此问题,我必须在匹配DecimalType之后再进行一些嗅探:

  case d: DecimalType =>
    // Oddly a column that matches to DecimalType can be of several different
    // class types and trying to getAs[Decimal] when it's a BigDecimal and/or
    // trying to getAs[BigDecimal] when the column is a Decimal results in an
    // exception, so make the right decision based on the instance class.
    val decimal = row.get(index) match {
      case bigDecimal: java.math.BigDecimal => Decimal(bigDecimal)
      case decimal: Decimal => decimal
      case _ => throw(
        new RuntimeException("Encountered unexpected decimal type")
      )
    }

知道decimal的类型为Decimal,您就可以从那里进行任何操作。