为什么在创建DataFrame时Spark会推断二进制而不是Array [Byte]?

时间:2018-10-31 01:24:37

标签: scala apache-spark binary apache-spark-sql user-defined-functions

原则上,我有一个{<1}},它由“ Name” “ Values” 字段组成。第一个字段是DataFrame,第二个字段是String

我要对此Array[Byte]的每个记录执行的操作是使用DataFrame应用任何函数并创建一个新列。当“值” UDF时,此方法非常有效。但是,当它是Array[Int]时,会出现以下错误:

Array[Byte]

完整代码如下:

org.apache.spark.sql.AnalysisException: cannot resolve 'UDF(Values)' due to data type mismatch: argument 1 requires array<tinyint> type, however, '`Values`' is of binary type.;;
'Project [Name#47, Values#48, UDF(Values#48) AS TwoTimes#56]
+- Project [_1#44 AS Name#47, _2#45 AS Values#48]
+- SerializeFromObject [staticinvoke(class 
org.apache.spark.unsafe.types.UTF8String, StringType, fromString, assertnotnull(assertnotnull(input[0, scala.Tuple2, true]))._1, true) AS _1#44, assertnotnull(assertnotnull(input[0, scala.Tuple2, true]))._2 AS _2#45]
  +- ExternalRDD [obj#43]

我知道由于错误的数据类型(预期:scala> val df1 = spark.sparkContext.parallelize(Seq(("one", Array[Byte](1, 2, 3, 4, 5)), ("two", Array[Byte](6, 7, 8, 9, 10)))).toDF("Name", "Values") df1: org.apache.spark.sql.DataFrame = [Name: string, Values: binary] scala> df1.show +----+----------------+ |Name| Values| +----+----------------+ | one|[01 02 03 04 05]| | two|[06 07 08 09 0A]| +----+----------------+ scala> val twice = udf { (values: Seq[Byte]) => | val result = Array.ofDim[Byte](values.length) | for (i <- values.indices) | result(i) = (2 * values(i).toInt).toByte | result | } twice: org.apache.spark.sql.expressions.UserDefinedFunction = UserDefinedFunction(<function1>,BinaryType,Some(List(ArrayType(ByteType,false)))) scala> val df2 = df1.withColumn("TwoTimes", twice('Values)) ,但是找到了Array[Byte]),会出现这样的错误,但是我不明白的是为什么Spark推断出我的{ {1}}作为Binary。有人可以向我解释吗?

如果我必须使用Array[Byte]而不是Binary,我应该如何在Binary中使用它?

我澄清说,我原来的Array[Byte]没有使用平凡的UDF循环。我了解在此示例中,可以用UDF方法代替。

1 个答案:

答案 0 :(得分:3)

在Spark中,Array[Byte]表示为BinaryType。从documentation我们可以看到:

  

公共类BinaryType扩展了DataType
  表示Array[Byte]值的数据类型。请使用单例DataTypes.BinaryType。

因此,Array[Byte]Binary相同,但是,它们与Seq[Byte]之间存在一些差异,这会导致错误。

要解决此问题,只需在udf中将Seq[Byte]替换为Array[Byte]

val twice = udf { (values: Array[Byte]) =>
  val result = Array.ofDim[Byte](values.length)
  for (i <- values.indices)
    result(i) = (2 * values(i).toInt).toByte
  result
}