2017-06-23 9 views
0

我正在使用sqlContext數據框架/ scala,並且已經成功地寫出了一些這些數據。我現在需要對另一個表進行正確連接,將其過濾爲只有我感興趣的數據。但是,當我嘗試編寫此連接表時,會導致NullPointerException。爲什麼連接兩個數據集並將其保存爲文本文件失敗,並返回NullPointerException?

這工作:

data 
    .select($"id", $"text") 
    .map(x => (x.getString(0), x.getString(1)).productIterator.mkString("\t")) 
    .saveAsTextFile("/hdfs/filepath/output.tsv") 

但這並不:

data 
    .join(data2, Seq("id"), "right") 
    .select($"id", $"text") 
    .map(x => (x.getString(0), x.getString(1)).productIterator.mkString("\t")) 
    .saveAsTextFile("/hdfs/filepath/output.tsv") 

堆棧跟蹤我得到的是:

Caused by: java.lang.NullPointerException 
at $iwC$$iwC$$iwC$$iwC$$iwC$$$$3d99ae6e19b65c7f617b22f29b431fb$$$$$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$anonfun$1.apply(<console>:150) 
at $iwC$$iwC$$iwC$$iwC$$iwC$$$$3d99ae6e19b65c7f617b22f29b431fb$$$$$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$iwC$$anonfun$1.apply(<console>:149) 
at scala.collection.Iterator$$anon$11.next(Iterator.scala:328) 
at scala.collection.Iterator$$anon$11.next(Iterator.scala:328) 
at org.apache.spark.rdd.PairRDDFunctions$$anonfun$saveAsHadoopDataset$1$$anonfun$13$$anonfun$apply$6.apply$mcV$sp(PairRDDFunctions.scala:1198) 
at org.apache.spark.rdd.PairRDDFunctions$$anonfun$saveAsHadoopDataset$1$$anonfun$13$$anonfun$apply$6.apply(PairRDDFunctions.scala:1197) 
at org.apache.spark.rdd.PairRDDFunctions$$anonfun$saveAsHadoopDataset$1$$anonfun$13$$anonfun$apply$6.apply(PairRDDFunctions.scala:1197) 
at org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1250) 
at org.apache.spark.rdd.PairRDDFunctions$$anonfun$saveAsHadoopDataset$1$$anonfun$13.apply(PairRDDFunctions.scala:1205) 
at org.apache.spark.rdd.PairRDDFunctions$$anonfun$saveAsHadoopDataset$1$$anonfun$13.apply(PairRDDFunctions.scala:1185) 
at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:66) 
at org.apache.spark.scheduler.Task.run(Task.scala:89) 
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:213) 
... 3 more 

運行這兩個...

data 
    .select($"id", $"text") 
    .printSchema 
data 
    .join(data2, Seq("id"), "right") 
    .select($"id", $"text") 
    .printSchema 

..results在同一個模式:

root 
|-- id: string (nullable = true) 
|-- text: string (nullable = true) 

如果我添加.show(5)表看起來是一樣的(不同之處在於加入了一個只包含我感興趣的數據)

+-------+--------+ 
| id | text| 
+-------+--------+ 
| 1 |some... | 
| 2 |text... | 
| 3 |here... | 
| 4 |foo... | 
| 5 |bar... | 
+-------+--------+ 
only showing top 5 rows 
+-------+--------+ 
| id | text| 
+-------+--------+ 
| 1 |some... | 
| 4 |foo... | 
| 5 |bar... | 
| 7 |other...| 
| 9 |stuff...| 
+-------+--------+ 
only showing top 5 rows 

我也嘗試加入到另一個表中:data.join(data3, Seq("id"), "right")並得到相同的NullPointerException錯誤。爲什麼?

+0

如果「productIterator」實際上是導致空指針異常的東西,那麼它必須看到下面的列表使用的是爲空:(x.getString(0) x.getString(1)) – TBowman

+0

@Towowman有道理 - 但爲什麼只有在表連接之後,productIterator纔會將列表視爲null? – clf

+0

我也試過'.take(1)。在.map語句之後(代替saveTextFile)使用foreach(println(_))',並且在這兩種情況下都會打印出id和text,所以列表不爲空。 – clf

回答

0

感謝@RameshMaharjan的提示,我意識到在我加入data和data2後有3個空值。事實證明,如果你有空值,那麼你將得到一個空指針異常... :)

不管怎麼說,2個選項,我發現修復:

1:內部連接,而不是外

data 
    .join(data2, Seq("id"), "inner") 
    .select($"id", $"text") 
    .map(x => (x.getString(0), x.getString(1)).productIterator.mkString("\t")) 
    .saveAsTextFile("/hdfs/filepath/output.tsv") 

2:擺脫空值

data 
    .join(data2, Seq("id"), "right") 
    .where($"id".isNotNull) 
    .select($"id", $"text") 
    .map(x => (x.getString(0), x.getString(1)).productIterator.mkString("\t")) 
    .saveAsTextFile("/hdfs/filepath/output.tsv") 
+0

謝謝你在回答中提及我:) –

0

(這可能不是確切的答案,但不能使用註釋來傳達的理念)


但這並不

的一點是,你創建一個元組只是爲了獲得可能不存在的值而立即解構它。

我會跟下面的重寫代碼:

data. 
    join(data2, Seq("id"), "right"). 
    select($"id", $"text"). 
    as[(String, String)]. // <-- Added explicit type conversion 
    map { case (id, text) => s"$id\t$text" }. 
    write. 
    text("/hdfs/filepath/output.tsv") 

這當然應該通過沒有例外,因爲您只需連接兩個字符串字段,並將其保存到一個文本文件。

+0

謝謝,亞採 - 這是一個好主意,但我想看看'值.saveAsTextFile不是org.apache.spark.sql.Dataset [字符串]的成員' – clf

+0

固定的代碼。對於那個很抱歉。我似乎已經用'as'將附加類型的代碼拷貝過來,而沒有檢查出來。 –

相關問題