我有一个csv文件[1],我想直接加载到数据集中。问题是我总是遇到像
这样的错误org.apache.spark.sql.AnalysisException: Cannot up cast `probability` from string to float as it may truncate
The type path of the target object is:
- field (class: "scala.Float", name: "probability")
- root class: "TFPredictionFormat"
You can either add an explicit cast to the input data or choose a higher precision type of the field in the target object;
此外,特别是phrases
字段(检查案例类[2]),它得到
org.apache.spark.sql.AnalysisException: cannot resolve '`phrases`' due to data type mismatch: cannot cast StringType to ArrayType(StringType,true);
如果我将我的case类[2]中的所有字段定义为String类型,那么一切正常,但这不是我想要的。有没有一种简单的方法可以做到[3]?
参考
[1]一个示例行
B017NX63A2,Merrell,"['merrell_for_men', 'merrell_mens_shoes', 'merrel']",merrell_shoes,0.0806054356579781
[2]我的代码片段如下
import spark.implicits._
val INPUT_TF = "<SOME_URI>/my_file.csv"
final case class TFFormat (
doc_id: String,
brand: String,
phrases: Seq[String],
prediction: String,
probability: Float
)
val ds = sqlContext.read
.option("header", "true")
.option("charset", "UTF8")
.csv(INPUT_TF)
.as[TFFormat]
ds.take(1).map(println)
[3]我已经找到了方法,首先在DataFrame级别定义列并将事物转换为数据集(如here或here或here)但我是几乎可以肯定,这不是应该做的事情。我也很确定编码器可能是答案,但我不知道如何
答案 0 :(得分:6)
TL; DR 使用csv
输入转换标准DataFrame
操作是可行的方法。如果你想避免使用具有表现力的输入格式(Parquet甚至是JSON)。
通常,要转换为静态类型数据集的数据必须已经是正确的类型。最有效的方法是为schema
读者提供csv
参数:
val schema: StructType = ???
val ds = spark.read
.option("header", "true")
.schema(schema)
.csv(path)
.as[T]
其中schema
可以通过反射来推断:
import org.apache.spark.sql.catalyst.ScalaReflection
import org.apache.spark.sql.types.StructType
val schema = ScalaReflection.schemaFor[T].dataType.asInstanceOf[StructType]
不幸的是,它不适用于您的数据和类,因为csv
读者不支持ArrayType
(但它适用于像FloatType
这样的原子类型,因此您必须使用困难的方式。一个天真的解决方案可以表达如下:
import org.apache.spark.sql.functions._
val df: DataFrame = ??? // Raw data
df
.withColumn("probability", $"probability".cast("float"))
.withColumn("phrases",
split(regexp_replace($"phrases", "[\\['\\]]", ""), ","))
.as[TFFormat]
但根据phrases
的内容,您可能需要更复杂的内容。