如何仅对 Spark 数据帧上的特定字段使用“立方体”?

Posted

技术标签:

【中文标题】如何仅对 Spark 数据帧上的特定字段使用“立方体”?【英文标题】:How to use "cube" only for specific fields on Spark dataframe? 【发布时间】:2016-11-23 11:30:30 【问题描述】:

我使用的是 Spark 1.6.1,我有这样一个数据框。

+-------------+-----------+-----------------+-------+-------+-------+----------+-------+-------+-------+-------+
|     scene_id|  action_id|       classifier|os_name|country|app_ver|   p0value|p1value|p2value|p3value|p4value|
+-------------+-----------+-----------------+-------+-------+-------+----------+-------+-------+-------+-------+
|    test_home|scene_enter|        test_home|android|     KR|  5.6.3|__OTHERS__|  false|   test|   test|   test|
......

我想通过多维数据集操作得到如下数据框。

(按所有字段分组,但只有“os_name”、“country”、“app_ver”字段被立方)

+-------------+-----------+-----------------+-------+-------+-------+----------+-------+-------+-------+-------+---+
|     scene_id|  action_id|       classifier|os_name|country|app_ver|   p0value|p1value|p2value|p3value|p4value|cnt|
+-------------+-----------+-----------------+-------+-------+-------+----------+-------+-------+-------+-------+---+
|    test_home|scene_enter|        test_home|android|     KR|  5.6.3|__OTHERS__|  false|   test|   test|   test|  9|
|    test_home|scene_enter|        test_home|   null|     KR|  5.6.3|__OTHERS__|  false|   test|   test|   test| 35|
|    test_home|scene_enter|        test_home|android|   null|  5.6.3|__OTHERS__|  false|   test|   test|   test| 98|
|    test_home|scene_enter|        test_home|android|     KR|   null|__OTHERS__|  false|   test|   test|   test|101|
|    test_home|scene_enter|        test_home|   null|   null|  5.6.3|__OTHERS__|  false|   test|   test|   test|301|
|    test_home|scene_enter|        test_home|   null|     KR|   null|__OTHERS__|  false|   test|   test|   test|225|
|    test_home|scene_enter|        test_home|android|   null|   null|__OTHERS__|  false|   test|   test|   test|312|
|    test_home|scene_enter|        test_home|   null|   null|   null|__OTHERS__|  false|   test|   test|   test|521|
......

我尝试过如下方式,但它似乎又慢又丑..

var cubed = df
  .cube($"scene_id", $"action_id", $"classifier", $"country", $"os_name", $"app_ver", $"p0value", $"p1value", $"p2value", $"p3value", $"p4value")
  .count
  .where("scene_id IS NOT NULL AND action_id IS NOT NULL AND classifier IS NOT NULL AND p0value IS NOT NULL AND p1value IS NOT NULL AND p2value IS NOT NULL AND p3value IS NOT NULL AND p4value IS NOT NULL")

有更好的解决方案吗?

【问题讨论】:

谢谢,但NULL 值是由cube 操作@CarlosVilchez 生成的... 【参考方案1】:

我相信你不能完全避免这个问题,但是有一个简单的技巧可以减少它的规模。这个想法是用一个占位符替换所有不应被边缘化的列。

例如,如果您有一个DataFrame

val df = Seq((1, 2, 3, 4, 5, 6)).toDF("a", "b", "c", "d", "e", "f")

并且您对被de 边缘化并按a..c 分组的立方体感兴趣,您可以将a..c 的替代定义为:

import org.apache.spark.sql.functions.struct
import sparkSql.implicits._

// alias here may not work in Spark 1.6
val rest = struct(Seq($"a", $"b", $"c"): _*).alias("rest")

cube:

val cubed =  Seq($"d", $"e")

// If there is a problem with aliasing rest it can done here.
val tmp = df.cube(rest.alias("rest") +: cubed: _*).count

快速过滤和选择应该处理其余的:

tmp.where($"rest".isNotNull).select($"rest.*" +: cubed :+ $"count": _*)

结果如下:

+---+---+---+----+----+-----+
|  a|  b|  c|   d|   e|count|
+---+---+---+----+----+-----+
|  1|  2|  3|null|   5|    1|
|  1|  2|  3|null|null|    1|
|  1|  2|  3|   4|   5|    1|
|  1|  2|  3|   4|null|    1|
+---+---+---+----+----+-----+

【讨论】:

以上是关于如何仅对 Spark 数据帧上的特定字段使用“立方体”?的主要内容,如果未能解决你的问题,请参考以下文章

具有大量列的数据帧上的 Spark 窗口函数

数据帧上的 spark GROUPED_MAP udf 是不是并行运行?

如何使用 spark-scala 在 spark 数据帧上执行枢轴?

如何仅对角度 2+ 中的特定字段应用动态字段验证

pyspark 数据帧上的向量操作

为什么过滤器在spark数据帧上默认删除空值?