【问题标题】:Creating a unique grouping key from column-wise runs in a Spark DataFrame从 Spark DataFrame 中的按列运行创建唯一的分组键
【发布时间】:2018-08-06 10:30:59
【问题描述】:

我有类似的东西,其中spark 是我的sparkContext。我在sparkContext 中导入了implicits._,所以我可以使用$ 语法:

val df = spark.createDataFrame(Seq(("a", 0L), ("b", 1L), ("c", 1L), ("d", 1L), ("e", 0L), ("f", 1L)))
              .toDF("id", "flag")
              .withColumn("index", monotonically_increasing_id)
              .withColumn("run_key", when($"flag" === 1, $"index").otherwise(0))

df.show

df: org.apache.spark.sql.DataFrame = [id: string, flag: bigint ... 2 more fields]
+---+----+-----+-------+
| id|flag|index|run_key|
+---+----+-----+-------+
|  a|   0|    0|      0|
|  b|   1|    1|      1|
|  c|   1|    2|      2|
|  d|   1|    3|      3|
|  e|   0|    4|      0|
|  f|   1|    5|      5|
+---+----+-----+-------+

我想为run_key 的每个非零块创建另一个具有唯一分组键的列,相当于:

+---+----+-----+-------+---+
| id|flag|index|run_key|key|
+---+----+-----+-------+---|
|  a|   0|    0|      0|  0|
|  b|   1|    1|      1|  1|
|  c|   1|    2|      2|  1|
|  d|   1|    3|      3|  1|
|  e|   0|    4|      0|  0|
|  f|   1|    5|      5|  2|
+---+----+-----+-------+---+

它可以是每次运行的第一个值、每次运行的平均值或某个其他值 - 只要保证它是唯一的,这样我就可以对其进行分组以比较其他值,这并不重要组之间。

编辑:顺便说一句,我不需要保留flag 是0 的行。

【问题讨论】:

    标签: scala apache-spark apache-spark-sql apache-spark-2.0


    【解决方案1】:

    一种方法是 1) 使用 Window 函数 lag() 从 $"flag" 创建列 $"lag1",2) 在 $"flag" 的行中创建具有 $"index" 值的另一列 $"switched" " 被切换,最后 3) 创建通过 last() 和 rowsBetween() 从最后一个非空行复制 $"switched" 的列。

    请注意,此解决方案使用 Window 函数而不进行分区,因此可能不适用于大型数据集。

    val df = Seq(
      ("a", 0L), ("b", 1L), ("c", 1L), ("d", 1L), ("e", 0L), ("f", 1L),
      ("g", 1L), ("h", 0L), ("i", 0L), ("j", 1L), ("k", 1L), ("l", 1L)
    ).toDF("id", "flag").
      withColumn("index", monotonically_increasing_id).
      withColumn("run_key", when($"flag" === 1, $"index").otherwise(0))
    
    import org.apache.spark.sql.expressions.Window
    
    df.withColumn( "lag1", lag("flag", 1, -1).over(Window.orderBy("index")) ).
      withColumn( "switched", when($"flag" =!= $"lag1", $"index") ).
      withColumn( "key", last("switched", ignoreNulls = true).over(
        Window.orderBy("index").rowsBetween(Window.unboundedPreceding, 0)
      ) )
    
    // +---+----+-----+-------+----+--------+---+
    // | id|flag|index|run_key|lag1|switched|key|
    // +---+----+-----+-------+----+--------+---+
    // |  a|   0|    0|      0|  -1|       0|  0|
    // |  b|   1|    1|      1|   0|       1|  1|
    // |  c|   1|    2|      2|   1|    null|  1|
    // |  d|   1|    3|      3|   1|    null|  1|
    // |  e|   0|    4|      0|   1|       4|  4|
    // |  f|   1|    5|      5|   0|       5|  5|
    // |  g|   1|    6|      6|   1|    null|  5|
    // |  h|   0|    7|      0|   1|       7|  7|
    // |  i|   0|    8|      0|   0|    null|  7|
    // |  j|   1|    9|      9|   0|       9|  9|
    // |  k|   1|   10|     10|   1|    null|  9|
    // |  l|   1|   11|     11|   1|    null|  9|
    // +---+----+-----+-------+----+--------+---+
    

    【讨论】:

    • 目前,最大大小约为 2M 行。我可以在未来重新审视更大的数据集(即创建/替换flag 的不同方法)。谢谢!
    【解决方案2】:

    您可以使用最大索引标记“运行”,其中flag 小于0 小于相关行的索引。

    类似:

    flags = df.filter($"flag" === 0)
      .select("index")
      .withColumnRenamed("index", "flagIndex")
    indices = df.select("index").join(flags, df.index > flags.flagIndex)
      .groupBy($"index")
      .agg(max($"index$).as("groupKey"))
    dfWithGroups = df.join(indices, Seq("index"))
    

    【讨论】:

      猜你喜欢
      • 2020-01-31
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      • 2018-09-20
      • 2019-07-08
      • 2021-12-08
      • 2023-03-04
      • 2018-08-25
      相关资源
      最近更新 更多