2016-07-07 14 views
1

のArrayにネストされたJSONを爆発私はそれは私に次のスキーマとデータフレーム与えスパークは、Scalaの

sqlContext.read.json("/hdfs/") 

を経てスパーク1.6にJSONファイルをロードしたとしましょう:

root 
|-- id: array (nullable = true) 
| |-- element: string (containsNull = true) 
|-- checked: array (nullable = true) 
| |-- element: string (containsNull = true) 
|-- color: array (nullable = true) 
| |-- element: string (containsNull = true) 
|-- type: array (nullable = true) 
| |-- element: string (containsNull = true) 

DFは一つだけを持っているが私の中のすべてのアイテムの配列を持つ行。

+--------------------+--------------------+--------------------+ 
|    id_e|   checked_e|    color_e| 
+--------------------+--------------------+--------------------+ 
|[0218797c-77a6-45...|[false, true, tru...|[null, null, null...| 
+--------------------+--------------------+--------------------+ 

配列を1行に1つに分解してDFを作成したいとします。

+--------------------+-----+-------+ 
|     id|color|checked| 
+--------------------+-----+-------+ 
|0218797c-77a6-45f...| null| false| 
|0218797c-77a6-45f...| null| false| 
|0218797c-77a6-45f...| null| false| 
|0218797c-77a6-45f...| null| false| 
|0218797c-77a6-45f...| null| false| 
|0218797c-77a6-45f...| null| false| 
|0218797c-77a6-45f...| null| false| 
|0218797c-77a6-45f...| null| false| 
... 

は、これまでのところ私は、これらのラインに爆発する側面図で配列DFと使用されるSQLからの一時テーブルを作成することによって、これを達成しました。

val results = sqlContext.sql(" 
SELECT id, color, checked from temptable 
lateral view explode(checked_e) temptable as checked 
lateral view explode(id_e) temptable as id 
lateral view explode(color_e) temptable as color 
") 

SQLを使用せずにDataframe関数でこれを直接実行する方法はありますか?私はdf.explode(...)のようなものがあると知っていますが、私のデータで動作させることができませんでした。

EDIT:私は本当に最初の場所で欲しいものではないようです。 配列の各項目を1行ずつ持つ新しいデータフレームが必要です。実際には、explode関数は私の初期のデータセットよりも多くの行を返します。

答えて

1

それは、このような単純なする必要があります:

df.withColumn("id", explode(col("id_e"))) 
    .withColumn("checked", explode(col("checked_e"))) 
    .withColumn("color", explode(col("color_e"))) 
+0

よくSQL文を使ってコードを実行しているようですが、チェックしてみると、この爆発は本当に必要なものではないとわかりました。私の最初のデータセットは〜600行です。爆発後、私は〜180ミルの線を持っています。私が実際に望むのは、新しいデータフレームを作成するために配列の要素を1行ずつ取り出すことです。 – user3780814

+0

正しいですが、私の答えはデカルトのように見えますが、@Rockie Yangのソリューションは正しい方法でそれを行うべきです –

3

以下のソリューションが動作するはずです。

import org.apache.spark.sql.Row 
import org.apache.spark.sql.functions._ 

val data = Seq((Seq(1,2,3),Seq(4,5,6),Seq(7,8,9))) 
val df = sqlContext.createDataFrame(data) 

val udf3 = udf[Seq[(Int, Int, Int)], Seq[Int], Seq[Int], Seq[Int]]{ 
    case (a, b, c) => (a,b, c).zipped.toSeq 
} 

val df3 = df.select(udf3($"_1", $"_2", $"_3").alias("udf3")) 
val exploded = df3.select(explode($"udf3").alias("col3")) 

exploded.withColumn("first", $"col3".getItem("_1")) 
    .withColumn("second", $"col3".getItem("_2")) 
    .withColumn("third", $"col3".getItem("_3")).show 

直接通常のScalaのコードを使用している場合、それはより簡単ですが。あまりにも効率的かもしれません。とにかく行が1つしかなければスパークは助けにならなかった。

関連する問題