首页 > 解决方案 > 避免在特定情况下使用 apache spark sql 的数据帧中具有相同域的多个列进行多次连接

问题描述

我被要求通过数据帧在 apache spark sql (java api) 中做一些事情,我认为如果按照幼稚的方法执行会花费很多(我仍在使用幼稚的方法,但我认为这会花费很多因为它至少需要 4 种连接)。

我得到以下数据框:

+----+----+----+----+----+----------+------+
|  C1|  C2|  C3|  C4|  C5|UNIQUE KEY|points|
+----+----+----+----+----+----------+------+
|   A|   A|null|null|null|      1234|     2|
|   A|null|null|   H|null|      1235|     3|
|   A|   B|null|null|null|      1236|     3|
|   B|null|null|null|   E|      1237|     1|
|   C|null|null|   G|null|      1238|     1|
|   F|null|   C|   E|null|      1239|     2|
|null|null|   D|   E|   G|      1240|     1|
+----+----+----+----+----+----------+------+

C1、C2、C3、C4 和 C5 具有相同的域值,唯一键是唯一键,点是一个整数,对于其对应 C 列的每个不同值(例如,对于第一行 A、A ,null,null,null,key,2 与 A,null,null,null,null,key,2 或 A,A,A,A,null,key,2 相同)

我被要求“为每个现有的 C 值获取总点数”。

所以输出应该是:

+----+------+
|  C1|points|
+----+------+
|   A|     8|
|   B|     4|
|   C|     3|
|   D|     1|
|   E|     4|
|   F|     2| 
|   G|     2|
|   H|     3|
+----+------+

我打算通过 simple 将数据框分成多个小数据框(C 列为 1 列,点为 1 列).select("C1","point").select("C2","point")依此类推。但是我相信如果数据量真的很大,那真的会花很多钱,我相信应该有一些通过map reduce的技巧,但我自己找不到,因为我对这一切还很陌生世界。我想我错过了一些关于如何应用地图缩减的概念。

我还考虑过使用该函数explode,我想将 [C1, C2, C3, C4, C5] 放在一列中然后使用explode所以我每行得到5行然后我只是按键分组......但我相信这会在某些时候增加数据量,如果我们谈论的是 GB,这可能不可行......我希望你能找到我正在寻找的技巧。

谢谢你的时间。

标签: javaapache-sparkapache-spark-sqlmapreduce

解决方案


使用explode可能是去这里的方式。与使用多个相比,它不会增加数据量并且在计算上更有效join(请注意,单个join本身是一项昂贵的操作)。

在这种情况下,您可以将列转换为数组,只保留每个单独行的唯一值。然后可以分解该数组并过滤掉所有空值。在这一点上,一个简单的groupBy和求和会给你想要的结果。

在斯卡拉:

df.select(explode(array_distinct(array("C1", "C2", "C3", "C4", "C5"))).as("C1"), $"points")
  .filter($"C1".isNotNull)
  .groupBy($"C1)
  .agg(sum($"points").as("points"))
  .sort($"C1") // not really necessary

这会给你想要的结果:

+----+------+
|  C1|points|
+----+------+
|   A|     8|
|   B|     4|
|   C|     3|
|   D|     1|
|   E|     4|
|   F|     2| 
|   G|     2|
|   H|     3|
+----+------+

推荐阅读