我正在测试一些原型应用程序。我们有嵌套字段的json数据。我正在尝试使用以下json和代码来拉取一些字段:
Feed: {name: "test",[Record: {id: 1 AllColumns: {ColA: "1",ColB: "2"}}...]}
Dataset<Row> completeRecord = sparkSession.read().json(inputPath);
final Dataset<Row> feed = completeRecord.select(completeRecord.col("Feed.Record.AllColumns"));
我有大约2000个包含此类记录的文件。我已经单独测试了一些文件,它们工作正常。但是对于某些文件,我在第二行上遇到错误:
org.apache.spark.sql.AnalysisException:无法从中提取值 Feed#8.Record:需要struct类型但是得到了字符串;
我不确定这里发生了什么。但是我想要优雅地处理这个错误并记录哪个文件有该记录。另外,有没有办法忽略这个并继续其余的文件?
答案 0 :(得分:2)
根据我所学的内容回答我自己的问题。有几种方法可以解决它。 Spark提供了忽略损坏文件和损坏记录的选项。
要忽略损坏的文件,可以将以下标志设置为true:
spark.sql.files.ignoreCorruptFiles =真
用于更细粒度的控制并忽略不良记录而不是忽略整个文件。您可以使用Spark api提供的三种模式之一。
根据DataFrameReader api
模式(默认 PERMISSIVE ):允许一种处理损坏的模式 解析期间的记录。 PERMISSIVE :将其他字段设置为null 遇到损坏的记录,并将格式错误的字符串放入新的字符串中 columnNameOfCorruptRecord配置的字段。架构设置时 user,为额外字段设置null DROPMALFORMED :忽略整体 记录损坏。
FAILFAST :遇到异常时抛出异常 损坏的记录。
PERMISSIVE模式对我来说效果非常好,但是当我提供自己的模式时,Spark使用null填充缺少的属性,而不是将其标记为损坏的记录。
答案 1 :(得分:1)
异常表示其中一个json文件的结构不同,并且此特定文件中不存在路径Feed.Record.AllColumns
。
基于此方法
private boolean pathExists(Dataset<Row> df, String path) {
try {
df.apply(path);
return true;
}
catch(Exception ex){
return false;
}
}
您可以决定是执行select
还是记录错误消息:
if(pathExists(completeRecord, "Feed.Record.AllColumns") {
final Dataset<Row> feed = completeRecord.select(completeRecord.col("Feed.Record.AllColumns"));
//continue with processing
}
else {
//log error message
}