在文件1中,/URI
元素“image”是嵌套的。数据看起来像这样结构:
/URI
Spark:
正确推断出结果模式JSON
文件nested2.json包含一些嵌套元素和一些非嵌套元素(在第二行下面,元素“image”未嵌套):
{"id": "0001", "type": "donut", "name": "Cake", "image":{"url": "images/0001.jpg", "width": 200, "height": 200}}
结果架构不包含嵌套数据:
val df1 = spark.read.json("/xxx/xxxx/xxxx/nested1.json")
df1.printSchema
root
|-- id: string (nullable = true)
|-- image: struct (nullable = true)
| |-- height: long (nullable = true)
| |-- url: string (nullable = true)
| |-- width: long (nullable = true)
|-- name: string (nullable = true)
|-- type: string (nullable = true)
为什么Spark存在非嵌套元素时无法找出架构?
如何使用Spark和Scala处理包含这类记录混合的{"id": "0001", "type": "donut", "name": "Cake", "image":{"url": "images/0001.jpg", "width": 200, "height": 200}}
{"id": "0002", "type": "donut", "name": "CupCake", "image": "images/0001.jpg"}
文件?
答案 0 :(得分:1)
通过不指定模式,Spark将通过读取数据一次从数据源推断出它。查看source code推断json
数据,代码中有一条评论:
分三个阶段推断json记录集合的类型:
- 推断每条记录的类型
- 通过选择覆盖相等键所需的最低类型来合并类型
- 将所有剩余的空字段替换为字符串,顶部类型
换句话说,当存在差异时,仅返回最常用的数据类型。通过混合嵌套和非嵌套类型,只返回非嵌套类型,因为所有行都包含这些值。
不是推断架构,而是自己创建架构并将其提供给方法。
val schema = StructType(
StructField("id", StringType, true) ::
StructField("type", StringType, true) ::
StructField("name", StringType, true) ::
StructField(
"image",
StructType(
StructField("height", LongType, true) ::
StructField("url", StringType, true) ::
StructField("width", LongType, true) ::
Nil
))
) :: Nil
)
然后在阅读时使用架构:
val df2 = spark.read
.schema(schema)
.json("/xxx/xxx/xxx/nested2.json")
但是,当它只是一个字符串时,这种方法将导致“image”字段的 null 。要获取这两种类型,请两次读取文件并合并结果。
val df3 = spark.read
.json("/xxx/xxx/xxx/nested2.json")
新数据框架与第一个架构有不同的架构。让它们相等,然后将数据帧合并在一起:
val df4 = df3.withColumn("image",
struct($"image".as("url"),
lit(0L).as("height"),
lit(0L).as("width"))
.select("id", "type", "name", "image")
val df5 = df2.union(df4)
最后select
用于确保列与df2
的顺序相同,否则union
将失败。