Scala - 当 Row.get(i) 将检索 null 时如何避免 java.lang.IllegalArgumentException
Posted
技术标签:
【中文标题】Scala - 当 Row.get(i) 将检索 null 时如何避免 java.lang.IllegalArgumentException【英文标题】:Scala - How to avoid java.lang.IllegalArgumentException when Row.get(i) would retrieve a null 【发布时间】:2018-02-05 11:24:48 【问题描述】:我正在使用 Spark 和 Scala 来读取一些 parquet 文件。我面临的问题是这个镶木地板文件的内容可能会有所不同,即某些字段有时不存在。因此,当我尝试访问文件中不存在的字段时,会出现以下异常:
java.lang.IllegalArgumentException:字段“wrongHeaderIndicator”确实 不存在。
我曾经在 Java 中做过类似的事情,可以使用 contains()
或 get(index)!= null
来检查我们尝试访问的字段是否存在。但我不能在 Scala 中做同样的事情。
您可以在下面看到我到目前为止所写的内容以及我尝试过的四件事,但均未成功。
//The part of reading the parquet file and accessing the rows works fine
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
import sqlContext.implicits._
val parquetFileDF = sqlContext.read.parquet("myParquet.parquet')
//I get one of the six blocks in the parquet file
val myHeaderData = parquetFileDF.select("HeaderData").collectAsList()
//When I try to access a particular field which is not in the "HeaderData"
//I get the exception
//1st Try
Option(myHeaderData.get(0).getStruct(0).getAs[String]("wrongHeaderIndicator")) match
case Some(i) => println("This data exist")
case None => println("This would be a null")
//2nd Try
if(myHeaderData.get(0).getStruct(0).getAs[String]("wrongHeaderIndicator")!= null)
println("This data exist")
else
println("This is null")
//3rd Try
println(myHeaderData.get(0).getStruct(0).fieldIndex("wrongHeaderIndicator"))
//4th Try
println(Some(myHeaderData.get(0).getStruct(0).getAs[String]("wrongHeaderIndicator")))
编辑。 问题不在于我访问 DataFrame 的列时。列总是相同的,我不需要在选择之前执行检查。一旦我访问特定列中记录的字段,问题就会出现。这些记录是您可以在下面看到的架构的结构:
myHeaderData 列的架构类似于:
|-- myHeaderData: struct (nullable = true)
| |-- myOpIndicator: string (nullable = true)
| |-- mySecondaryFlag: string (nullable = true)
| |-- myDownloadDate: string (nullable = true)
| |-- myDownloadTime: string (nullable = true)
| |-- myUUID: string (nullable = true)
如果我跑了
myHeaderData.get(0).getStruct(0).schema
我得到以下输出:
StructType(StructField(myOpIndicator,StringType,true), StructField(mySecondaryFlag,StringType,true), StructField(myDownloadDate,StringType,true), StructField(myDownloadTime,StringType,true), StructField(myUUID,StringType,true))
我尝试的四件事产生了相同的异常。谁能告诉我我可以用什么来检查结构中是否存在字段而不生成异常?
谢谢
【问题讨论】:
我想提一下,我确实已经在 *** 中寻找过这个问题,但我找不到解决问题的方法。如果有人可以向我推荐一个已经回答的问题,请将其添加到此评论中,我将自行关闭此问题。 您似乎正在尝试查找“wrongHeaderIndicator”并比较其输出。但是你应该检查“wrongHeaderIndicator”本身是否存在。 @Gabain1993 是的。如果存在,我该如何检查它 @user8371915,没有。我确实知道如何检测数据图中是否有列。这里我想要检查结构内是否有元素。 【参考方案1】:你的假设是错误的。如果getAs
字段不存在,它会抛出异常,而不是返回null
。因此你应该使用Try
:
import scala.util.Try, Success, Failure
import org.apache.spark.sql.Row
val row: Row = spark.read.json(sc.parallelize(Seq(
""""myHeaderData": "myOpIndicator": "foo""""))).first
Try(row.getAs[Row]("myHeaderData").getAs[String]("myOpIndicator")) match
case Success(s) => println(s)
case _ => println("error")
【讨论】:
谢谢。 Try 而不是 Option 成功了,不再有例外。【参考方案2】:您可以轻松检查数据框中是否存在列。使用df.columns
方法获取包含数据中所有标题的数组,然后检查您的列(wrongHeaderIndicator
)是否在数组中。这是一个简短的例子:
val df = Seq(("aaa", "123"), ("bbb", "456"), ("ccc", "789")).toDF("col1", "col2")
df.show()
+----+----+
|col1|col2|
+----+----+
| aaa| 123|
| bbb| 456|
| ccc| 789|
+----+----+
现在使用df.columns.toList
将为您提供List(col1, col2)
。要检查您的字段是否存在,只需执行df.columns.contains("fieldName")
。
【讨论】:
感谢您的回复,但该部分已在我发布的代码中得到解决,myHeaderData 已经是一列。问题在于下一步。每列有几条记录,每条记录是一个结构,可能包含1到5个字段。有时所有 5 个字段都存在,有时不存在。而且我遇到了问题 @IgnacioAlorre 啊,我明白了。我一定是误会你了。你能发布一些结构的例子吗?以上是关于Scala - 当 Row.get(i) 将检索 null 时如何避免 java.lang.IllegalArgumentException的主要内容,如果未能解决你的问题,请参考以下文章
Spark (Scala) 中的 K-means - 当模型由标准化数据制作时,如何将集群编号映射回客户 ID