将索引列添加到现有Spark的DataFrame

时间:2016-08-10 14:00:09

标签: java apache-spark

我使用Java运行Spark 1.5。我需要将ID / Index列附加到现有的DataFrame,例如:

+---------+--------+
|  surname|    name|
+---------+--------+
|    Green|    Jake|
| Anderson|  Thomas|
| Corleone| Michael|
|    Marsh|   Randy|
|  Montana|    Tony|
|    Green|   Julia|
|Brenneman|    Eady|
|   Durden|   Tyler|
| Corleone|    Vito|
|   Madiro|     Mat|
+---------+--------+

我希望每行都附加索引,范围在介于1和表记录之间之间。索引顺序无关紧要,任何行都必须只包含唯一的ID /索引。它可以通过转换为RDD并将索引行和转换附加到具有修改的StructType的DataFrame来完成,但是,如果我理解正确,此操作会消耗大量资源用于转换等,并且必须有另一种方式。 结果必须如下:

+---------+--------+---+
|  surname|    name| id|
+---------+--------+---+
|    Green|    Jake|  3|
| Anderson|  Thomas|  5|
| Corleone| Michael|  2|
|    Marsh|   Randy| 10|
|  Montana|    Tony|  7|
|    Green|   Julia|  1|
|Brenneman|    Eady|  2|
|   Durden|   Tyler|  9|
| Corleone|    Vito|  4|
|   Madiro|     Mat|  6|
+---------+--------+---+

谢谢。

5 个答案:

答案 0 :(得分:2)

我知道这个问题可能还有一段时间,但您可以按照以下方式进行:

from pyspark.sql.window import Window  
w = Window.orderBy("myColumn") 
withIndexDF = originalDF.withColumn("index", row_number().over(w))
  • myColumn :数据框中的任何特定列。
  • originalDF :没有索引列的原始DataFrame。

答案 1 :(得分:0)

伙计们,这是一个很好的方法:

DataFrame-ified zipWithIndex

从RDD模拟ZipWithIndex方法...第一个建议表现更好,但到目前为止纯粹的Dataframes解决方案没有大问题(在我的场景中超过100M行表)。

答案 2 :(得分:0)

在Scala中,首先我们需要创建一个索引数组:

val indx_arr=(1 to your_df.count.toInt).toArray

indx_arr: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

现在,我们要将此列附加到Dataframe。 首先,我们打开我们的Dataframe并将其作为数组获取,然后我们使用indx_arr将其压缩,然后将新创建的数组转换回RDD。最后一步是将其作为Dataframe:

final_df = sc.parallelize((your_df.collect.map(
    x=>(x(0),x(1))) zip indx_arr).map(
    x=>(x._1._1.toString,x._1._2.toString,x._2))).toDF("surname","name","id")

这也是一种简单直接的方法,可以将任何类型的数组附加到Spark Dataframe。

答案 3 :(得分:0)

在spark数据框中执行此操作的最简洁方法:

.withColumn("idx",monotonically_increasing_id())

完整文档:https://docs.databricks.com/spark/latest/sparkr/functions/withColumn.html

答案 4 :(得分:-2)

您可以使用withColumn功能。用法应该是Val myDF = existingDF.withColumn(" index",express(random(1,existingDF.count())