次の分解クエリがありますが、正常に機能します。
data1 = sqlContext.sql("select explode(names) as name from data")
別のフィールド「色」を分解したいので、最終的な出力は名前と色のデカルト積になります。だから私はしました:
data1 = sqlContext.sql("select explode(names) as name, explode(colors) as color from data")
しかし、私はエラーを受け取りました:
Only one generator allowed per select but Generate and and Explode found.;
誰かが何か考えを持っていますか?
2つのステップを実行することで、実際に機能させることができます。
data1 = sqlContext.sql("select explode(names) as name from data")
data1.registerTempTable('data1')
data1 = sqlContext.sql("select explode(colors) as color from data1")
しかし、私はそれを1つのステップで行うことが可能かどうか疑問に思っていますか?どうもありがとう!
正しい構文は
_select name, color
from data
lateral view explode(names) exploded_names as name
lateral view explode(colors) exploded_colors as color
_
Rashidの回答が機能しなかった理由は、_LATERAL VIEW
_によって生成されたテーブルに「名前」を付けなかったためです。
このように考える:_LATERAL VIEW
_は暗黙のJOIN
のように機能し、コレクション内のstructs
からのすべての行に対して作成された一時テーブルが "表示"されます。したがって、構文を解析する方法は次のとおりです。
_LATERAL VIEW table_generation_function(collection_column) table_name AS col1, ...
_
posexplode()
などのテーブル生成関数を使用する場合、出力テーブルは1つですが、複数の出力列があります。
_LATERAL VIEW posexplode(orders) exploded_orders AS order_number, order
_
ネストされたコレクションを繰り返し展開することで_LATERAL VIEW
_を「ネスト」することもできます。たとえば、
_LATERAL VIEW posexplode(orders) exploded_orders AS order_number, order
LATERAL VIEW posexplode(order.items) exploded_items AS item_number, item
_
_LATERAL VIEW
_のトピックについては、SparkSQL経由で使用する方がDataFrame
DSL経由で使用するよりも効率的であることに注意してください(例:myDF.explode()
)。その理由は、DSL APIが言語タイプとデータフレーム行の間のタイプ変換を実行する必要がある一方で、SQLがスキーマについて正確に推論できるためです。 DSL APIがパフォーマンスの面で失うものは何ですか。ただし、explode
からサポートされている型を返すことができるため、柔軟性が向上します。つまり、より複雑な変換を1つのステップで実行できます。
Sparkの最近のバージョンでは、df.explode()
による行レベルの分解が廃止され、df.select(..., explode(...).as(...))
による列レベルの分解が優先されます。 explode_outer()
もあり、展開される入力がnull
であっても出力行を生成します。 Sparkは内部行データ表現を使用して完全に変換を実行できるため、列レベルの爆発は、上記の行レベルの爆発のパフォーマンスの問題の影響を受けません。
代わりに側面図を分解してみてください。
select name, color from data lateral view explode(names) as name lateral view explode(colors) as color;
spark sqlでは混乱を招くため、複数の分解は許可されていません。これは、爆発している2つのものの暗黙のデカルト積を取得するためです。複数の操作を実行する場合爆発すると、複数の選択を使用する必要があります。Hiveには、必要なものを達成できる側面ビューがあります(ここでのRashid ALiの回答で説明されています)。ここで、「データ」がデータフレームであると仮定します。
val data1 = data.select($"id",$"names",$explode($"colors").alias("colors"))
//select required columns from colors
.select($"id",$"colors.field1",explode($"names").alias("names"))
//now select required cols from names
.select($"id",$"field1",$"names.col1",$"names.col2")
複数のデータフレームまたは上記のような単一のデータフレームで上記の選択を行うことができますが、パフォーマンスに影響はありません。
df.withColumn
を使用して複数の列を分解する簡単な方法があります。
scala> val data = spark.sparkContext.parallelize(Seq((Array("Alice", "Bob"), Array("Red", "Green", "Blue"))))
.toDF("names", "colors")
data: org.Apache.spark.sql.DataFrame = [names: array<string>, colors: array<string>]
scala> data.show
+------------+------------------+
| names| colors|
+------------+------------------+
|[Alice, Bob]|[Red, Green, Blue]|
+------------+------------------+
scala> data.withColumn("name", explode('names))
.withColumn("color", explode('colors))
.show
+------------+------------------+-----+-----+
| names| colors| name|color|
+------------+------------------+-----+-----+
|[Alice, Bob]|[Red, Green, Blue]|Alice| Red|
|[Alice, Bob]|[Red, Green, Blue]|Alice|Green|
|[Alice, Bob]|[Red, Green, Blue]|Alice| Blue|
|[Alice, Bob]|[Red, Green, Blue]| Bob| Red|
|[Alice, Bob]|[Red, Green, Blue]| Bob|Green|
|[Alice, Bob]|[Red, Green, Blue]| Bob| Blue|
+------------+------------------+-----+-----+