我有一个包含多个JSON对象的文件,其中包含以下架构:
{A: struct, B: struct, C: struct, D: struct}
使用A
的值永远不为空的属性;但是,B, C,
或D
中只有一个也可以是非空的。例如,我们会在数据框中看到类似的内容:
+----+----+----+----+
| A | B | C | D |
+----+----+----+----+
|[..]|[..]|null|null|
|[..]|null|[..]|null|
|[..]|null|null|[..]|
+----+----+----+----+
我尝试按A
对数据框进行分组,同时保持(A,B,C,D)
的相同模式/列结构,使得给定行中的所有值都为非空。
A
和任何B,C,D
之间可能存在多对一关系,在这种情况下,我会将架构更改为
{A: struct, B: list, C: list, D: list}
,但仍保留列名称。
我对Spark和Scala相当新,并且只能以程序的方式构建我的想法,我遍历每一行并在A
上散列,然后以这种方式构建一个完整的行,但是我&#39 ;我不相信它是一个干净的解决方案,我也无法使用spark API有效地表达它。
答案 0 :(得分:0)
评论部分有点笨拙,所以这里有一个如何做到这一点的例子
scala> case class Foo(a:String, b:String, c:String)
defined class Foo
scala> val ds = spark.createDataset(List(Foo("1","1",null), Foo("1",null,null), Foo("1","3",null), Foo("1", null, null)))
ds: org.apache.spark.sql.Dataset[Foo] = [a: string, b: string ... 1 more field]
scala> val collected = ds.groupBy(ds("a")).agg(collect_list(ds("b")).alias("b"), collect_list(ds("c")).alias("c"))
collected: org.apache.spark.sql.DataFrame = [a: string, b: array<string> ... 1 more field]
scala> val filtered = collected.where(size(collected("b")) > 0 and size(collected("c")) > 0)
filtered: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [a: string, b: array<string> ... 1 more field]
scala> collected.show
+---+------+---+
| a| b| c|
+---+------+---+
| 1|[1, 3]| []|
+---+------+---+
scala> filtered.show
+---+---+---+
| a| b| c|
+---+---+---+
+---+---+---+
答案 1 :(得分:0)
val df = spark.createDataFrame(
sc.parallelize(Seq(Row(1, 2, 3, 4), Row(1, 3, 4, null), Row(2, null, 4, null), Row(2, 2, 2, null))),
StructType(Seq("A","B","C","D").map(StructField(_, IntegerType, true )))
)
df.show()
+---+----+---+----+
| A| B| C| D|
+---+----+---+----+
| 1| 2| 3| 4|
| 1| 3| 4|null|
| 2|null| 4|null|
| 2| 2| 2|null|
+---+----+---+----+
df
.groupBy("A")
.agg(collect_list('B) as "B", collect_list('C) as "C",collect_list('D) as "D")
.show
+---+------+------+---+
| A| B| C| D|
+---+------+------+---+
| 1|[2, 3]|[3, 4]|[4]|
| 2| [2]|[4, 2]| []|
+---+------+------+---+
默认情况下,collect_list不会收集空值,这正是您想要的(如果所有值都为null,您将获得一个空列表)。使用collect_set可以避免重复。