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

scala 第一课

从Resultset scala中检索对象数组

当 `this` 不可用时,从拖动回调中检索 DOM 目标

scala基础题--100以内的数求和,求出当和第一次大于20的当前数for

scala 闭包的概念