假设您有一堆数据,其行如下所示:
{
'key': [
{'key1': 'value11', 'key2': 'value21'},
{'key1': 'value12', 'key2': 'value22'}
]
}
我想把它读成Spark Dataset
。一种方法如下:
case class ObjOfLists(k1: List[String], k2: List[String])
case class Data(k: ObjOfLists)
然后你可以这样做:
sparkSession.read.json(pathToData).select(
struct($"key.key1" as "k1", $"key.key2" as "k2") as "k"
)
.as[Data]
这样可以正常工作,但它有点扼杀数据;毕竟在数据'key'
中指向对象列表而不是列表对象。换句话说,我真正想要的是:
case class Obj(k1: String, k2: String)
case class DataOfList(k: List[Obj])
我的问题:我可以在select
中添加一些其他语法,以便将生成的Dataframe
转换为Dataset[DataOfList]
吗?
我尝试使用与上面相同的select
语法,并得到:
线程“main”中的异常org.apache.spark.sql.AnalysisException:需要一个数组字段但得到
struct<k1:array<string>,k2:array<string>>;
所以我也试过了:
sparkSession.read.json(pathToData).select(
array(struct($"key.key1" as "k1", $"key.key2" as "k2")) as "k"
)
.as[DataOfList]
这会编译并运行,但数据如下所示:
DataOfList(列表(的OBJ(org.apache.spark.sql.catalyst.expressions.UnsafeArrayData @ bb2a5516,org.apache.spark.sql.catalyst.expressions.UnsafeArrayData @ bec5e4a7)))
还有其他想法吗?
答案 0 :(得分:0)
重新制作数据以反映预期的名称:
case class Obj(k1: String, k2: String)
case class DataOfList(k: Seq[Obj])
val text = Seq("""{
"key": [
{"key1": "value11", "key2": "value21"},
{"key1": "value12", "key2": "value22"}
]
}""").toDS
val df = spark.read.json(text)
df
.select($"key".cast("array<struct<k1:string,k2:string>>").as("k"))
.as[DataOfList]
.first
DataOfList(List(Obj(value11,value21), Obj(value12,value22)))
使用无关对象,您可以在read:
上定义模式val textExtended = Seq("""{
"key": [
{"key0": "value01", "key1": "value11", "key2": "value21"},
{"key1": "value12", "key2": "value22", "key3": "value32"}
]
}""").toDS
val schemaSubset = StructType(Seq(StructField("key", ArrayType(StructType(Seq(
StructField("key1", StringType),
StructField("key2", StringType))))
)))
val df = spark.read.schema(schemaSubset).json(textExtended)
并像以前一样继续。