【问题标题】:DecimalType issue while creating Dataframe创建 Dataframe 时出现 DecimalType 问题
【发布时间】:2017-08-16 15:19:09
【问题描述】:

当我尝试使用十进制类型创建数据框时,它向我抛出了以下错误。

我正在执行以下步骤:

import org.apache.spark.sql.Row;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
import org.apache.spark.sql.types.StringType;
import org.apache.spark.sql.types.DataTypes._;


//created a DecimalType
val DecimalType = DataTypes.createDecimalType(15,10)

//创建架构

val sch = StructType(StructField("COL1",StringType,true)::StructField("COL2",**DecimalType**,true)::Nil)

val src = sc.textFile("test_file.txt")
val row = src.map(x=>x.split(",")).map(x=>Row.fromSeq(x))
val df1= sqlContext.createDataFrame(row,sch)

df1 的创建没有任何错误。但是,当我作为 df1.collect() 操作发出时,它给了我以下错误:

scala.MatchError: 0 (of class java.lang.String)
    at org.apache.spark.sql.catalyst.CatalystTypeConverters$DecimalConverter.toCatalystImpl(CatalystTypeConverters.scala:326)

test_file.txt 内容:

test1,0
test2,0.67
test3,10.65
test4,-10.1234567890

我创建 DecimalType 的方式有什么问题吗?

【问题讨论】:

  • 将所有内容读取为 StringType 并稍后转换为 DecimalType。

标签: scala apache-spark dataframe


【解决方案1】:

您应该有一个 BigDecimal 的实例来转换为 DecimalType

val DecimalType = DataTypes.createDecimalType(15, 10)
val sch = StructType(StructField("COL1", StringType, true) :: StructField("COL2", DecimalType, true) :: Nil)

val src = sc.textFile("test_file.txt")
val row = src.map(x => x.split(",")).map(x => Row(x(0), BigDecimal.decimal(x(1).toDouble)))

val df1 = spark.createDataFrame(row, sch)
df1.collect().foreach { println }
df1.printSchema()

结果如下:

[test1,0E-10]
[test2,0.6700000000]
[test3,10.6500000000]
[test4,-10.1234567890]
root
 |-- COL1: string (nullable = true)
 |-- COL2: decimal(15,10) (nullable = true)

【讨论】:

  • 感谢您的回答。看起来它正在工作。但是,我遇到了以下问题: scala> val row2= src.map(x => x.split(",")).map(x=>Row(x(0),BigDecimal.decimal(x(1) ).toDouble))) :34: error: value decimal 不是 object scala.math.BigDecimal val row2= src.map(x => x.split(",")).map(x =>行(x(0),BigDecimal.decimal(x(1).toDouble)))。所以我尝试过: val row2= src.map(x => x.split(",")).map(x=>Row(x(0),BigDecimal(x(1).toDouble))) 和我能够得到结果。第一个值显示为“0E-10”而不是 0 的任何原因。
  • 1. BigDecimal() 等价于 BigDecimal.decimal()。
  • 2.显示为“0E-10”,因为类型是十进制。 BigDecimal(0) 打印 0,但 BigDecimal(0: Double) 应该打印 0.0
【解决方案2】:

当您以sc.textFile 读取文件时,它会将所有值读取为string,因此错误是由于在创建dataframe 时应用schema 造成的

为此,您可以在应用schema 之前将第二个值转换为Decimal

val row = src.map(x=>x.split(",")).map(x=>Row(x(0), BigDecimal.decimal(x(1).toDouble)))

或者,如果您读取的是 cav 文件,那么您可以使用 spark-csv 读取 csv 文件并在读取文件时提供架构。

val df = sqlContext.read
    .format("com.databricks.spark.csv")
    .option("header", "true") // Use first line of all files as header
    .option("inferSchema", "true") // Automatically infer data types
    .load("cars.csv")

对于 Spark > 2.0

spark.read
      .option("header", true)
      .schema(sch)
      .csv(file)

希望这会有所帮助!

【讨论】:

  • 第一种方法不起作用,至少在 Spark 1.6 上不起作用。
  • 您的建议与 cstur4 的建议相同。你们俩都是对的。如果您知道为什么 0 在上面提供的答案中显示为 0E-10,请告诉我。
【解决方案3】:

解决问题的更简单方法是将 csv 文件直接加载为数据框。你可以这样做:

val df = sqlContext.read.format("com.databricks.spark.csv")
  .option("header", "false") // no header
  .option("inferSchema", "true")
  .load("/file/path/")

或者对于 Spark > 2.0:

val spark = SparkSession.builder.getOrCreate()
val df = spark.read
  .format("com.databricks.spark.csv")
  .option("header", "false") // no headers
  .load("/file/path")

输出:

df.show()

+-----+--------------+
|  _c0|           _c1|
+-----+--------------+
|test1|             0|
|test2|          0.67|
|test3|         10.65|
|test4|-10.1234567890|
+-----+--------------+

【讨论】:

    猜你喜欢
    • 2022-01-26
    • 1970-01-01
    • 1970-01-01
    • 2020-05-23
    • 1970-01-01
    • 2013-04-17
    • 2021-04-09
    • 1970-01-01
    • 2010-12-04
    相关资源
    最近更新 更多