2つのフィールドがある_object_id: String
_と_alpha: Map<>
_という寄木細工のファイルにデータがあります。
これは、sparkSQLのデータフレームに読み込まれ、スキーマは次のようになります。
_scala> alphaDF.printSchema()
root
|-- object_id: string (nullable = true)
|-- ALPHA: map (nullable = true)
| |-- key: string
| |-- value: struct (valueContainsNull = true)
_
私はSpark 2.0を使用しており、列を_object_id
_に加えて_ALPHA
マップのキーにする必要がある新しいデータフレームを_object_id, key1, key2, key2, ...
_
私は最初に、少なくとも次のようにマップにアクセスできるかどうかを確認しようとしました。
_scala> alphaDF.map(a => a(0)).collect()
<console>:32: error: Unable to find encoder for type stored in a Dataset.
Primitive types (Int, String, etc) and Product types (case classes) are
supported by importing spark.implicits._ Support for serializing other
types will be added in future releases.
alphaDF.map(a => a(0)).collect()
_
しかし残念ながら、マップのキーにアクセスする方法を理解することができないようです。
誰かが_object_id
_およびマップキーを列名として取得し、値を新しいデータフレームのそれぞれの値として取得する方法を教えてもらえますか?
スパーク> = 2.
map_keys
関数を使用してプロセスを簡略化できます。
import org.Apache.spark.sql.functions.map_keys
map_values
関数もありますが、ここでは直接役立ちません。
スパーク<2.
一般的な方法は、数ステップで表現できます。最初に必要なインポート:
import org.Apache.spark.sql.functions.udf
import org.Apache.spark.sql.Row
およびサンプルデータ:
val ds = Seq(
(1, Map("foo" -> (1, "a"), "bar" -> (2, "b"))),
(2, Map("foo" -> (3, "c"))),
(3, Map("bar" -> (4, "d")))
).toDF("id", "alpha")
キーを抽出するには、UDFを使用できます(Spark <2.3)
val map_keys = udf[Seq[String], Map[String, Row]](_.keys.toSeq)
または組み込み関数
import org.Apache.spark.sql.functions.map_keys
val keysDF = df.select(map_keys($"alpha"))
異なるものを見つける:
val distinctKeys = keysDF.as[Seq[String]].flatMap(identity).distinct
.collect.sorted
keys
をexplode
で一般化することもできます:
import org.Apache.spark.sql.functions.explode
val distinctKeys = df
// Flatten the column into key, value columns
.select(explode($"alpha"))
.select($"key")
.as[String].distinct
.collect.sorted
そしてselect
:
ds.select($"id" +: distinctKeys.map(x => $"alpha".getItem(x).alias(x)): _*)
そして、あなたがPySparkにいるなら、私は簡単な実装を見つけます:
from pyspark.sql.functions import map_keys
alphaDF.select(map_keys("ALPHA").alias("keys")).show()
詳細は こちら で確認できます