spark中的DataFrame.show()方法中的java.NullPointException - scala

时间:2015-11-27 09:16:32

标签: json scala nullpointerexception apache-spark spark-dataframe

编辑:对于以前的问题质量感到抱歉,我希望这个问题会更清楚: 使用Spark应用程序,我正在加载以下JSON文件的整个目录:

    {
        "type": "some_type",
        "payload": {
            "data1": {
                "id": "1"           
            },
            "data2": {
                "id": "1",

            },
            "data3": {
                "id": "1"
            },
            "dataset1": [{
                "data11": {
                    "id": "1",
                },
                "data12": {
                    "id": "1",
                }
            }],
            "masterdata": {
                "md1": [{
                    "id": "1"
                },
                {
                    "id": "2"
                },
                {
                    "id": "3"
                }],
                "md2": [{
                    "id": "1",
                },
                {
                    "id": "2",
                },
                {
                    "id": "3",
                }]
            }
        }
    }

DataFrame并保存为临时表以便以后使用它。在此Json中,“payload”节点中的字段始终存在,但“masterdata”中的子节点是可选的。 下一步是为Json的每个子节点创建多个DataFrame,如下所示: DataFrame data1包含来自所有文件的节点“data1”的数据,看起来像具有列“id”的常规表。 在第一次处理部分后,我的Spark状态如下: DataFrames:     DATA1(ID),     DATA2(ID),     DATA3(ID),     DATA11(ID),     DATA12(ID),     MD1(ID),     MD2(ID)

出现问题 - 如果目录中的一个JSON文件不包含md2节点,由于NullPointException,我无法在“md2”DataFrame上运行show()collect()。 我会理解,如果所有文件都缺少“md2”节点,那么它无法创建md2 DataFrame,但在这种情况下,我希望md2 DataFrame根本没有来自没有节点md2但包含所有其他节点的json文件的数据。

技术细节: 要从嵌套节点读取数据,我使用的是rdd.map& rdd.flatmap,然后我用自定义列名将其转换为DataFrame

如果我在目录中的所有文件包含所有节点时运行应用程序一切正常,但如果缺少单个文件md2节点应用程序失败.show()或.collect()

BTW如果节点存在但空的一切正常。

有没有办法让Spark支持可选的Json节点或处理rdd.map& flatmap中缺少的节点?

我希望它比以前的问题更清楚

在@Beryllium请求中,这里是我用来获取md2 DataFrame的rdd操作

    val jsonData = hiveContext.sql("SELECT `payload`.masterdata.md2 FROM jsonData")
    val data = jsonData.rdd.flatMap(row => row.getSeq[Row](0)).map(row => (
    row.getString(row.fieldIndex("id"))
    )).distinct
    val dataDF = data.toDF("id")    

1 个答案:

答案 0 :(得分:2)

快速修复

尝试插入filter(),如下所示:

sqlContext.sql("SELECT payload.masterdata.md2 FROM jsonData")
  .rdd
  .filter(_.getSeq[Row](0) != null)
  .flatMap(row => row.getSeq[Row](0))
  .map(row => (row.getString(row.fieldIndex("id"))))
  .distinct
  .toDF("id")
  .show()

使用explode()

这会尽快删除空值:所以它应该更快(至少它更短):

sqlContext
  .sql("select t.a.id from (SELECT explode(payload.masterdata.md2) as a FROM jsonData) t")
  • explode()爆炸了null
  • 然后子查询仅提取ID

更简单:首先提取ID,然后提取explode()

sqlContext.sql("SELECT explode(payload.masterdata.md2.id) FROM jsonData").show()