是否有可能以及将数据库添加到数据框的最有效的方法是什么?
更具体地说,列可以作为现有数据框的行ID。
在简化的情况下,从文件读取而不是标记它,我可以想到如下(在Scala中),但它完成有错误(在第3行),并且无论如何看起来不是最好的路线:
var dataDF = sc.textFile("path/file").toDF()
val rowDF = sc.parallelize(1 to DataDF.count().toInt).toDF("ID")
dataDF = dataDF.withColumn("ID", rowDF("ID"))
答案 0 :(得分:50)
自从我发布问题以来已经有一段时间了,似乎其他一些人也希望得到答案。以下是我发现的内容。
因此,最初的任务是将一个带有行标识符的列(基本上是一个序列1 to numRows
)附加到任何给定的数据帧,因此可以跟踪行的顺序/存在(例如,当您进行采样时)。这可以通过以下方式实现:
sqlContext.textFile(file).
zipWithIndex().
map(case(d, i)=>i.toString + delimiter + d).
map(_.split(delimiter)).
map(s=>Row.fromSeq(s.toSeq))
关于将任何列附加到任何数据框的一般情况:
"最近" Spark API中的此功能包括withColumn
和withColumnRenamed
。根据{{3}},前通过添加列返回新的DataFrame。在我看来,这是一个有点混乱和不完整的定义。这两个函数都只能在this
数据框上运行,即给定两个数据框df1
和df2
列col
:
val df = df1.withColumn("newCol", df1("col") + 1) // -- OK
val df = df1.withColumn("newCol", df2("col") + 1) // -- FAIL
因此,除非您能够将现有数据框中的列转换为所需的形状,否则您无法使用withColumn
或withColumnRenamed
附加任意列(独立或其他数据框) )。
正如上面评论的那样,解决方法可能是使用join
- 这可能会非常混乱,尽管可能 - 将上面的唯一键与zipWithIndex
一起附加到数据框或列可能有用。虽然效率很高......
很明显,在数据框中附加一个列并不是分布式环境的简单功能,可能根本就没有非常有效,简洁的方法。但我认为,即使有性能警告,提供此核心功能仍然非常重要。
答案 1 :(得分:27)
不确定它是否适用于spark 1.3但是在spark 1.5中我使用了withColumn:
import sqlContext.implicits._
import org.apache.spark.sql.functions._
df.withColumn("newName",lit("newValue"))
当我需要使用与数据帧的现有列
无关的值时,我会使用它这类似于@ NehaM的答案,但更简单
答案 2 :(得分:6)
我从上面的回答中得到了帮助。但是,如果我们想要更改DataFrame
并且当前API在Spark 1.6
中略有不同,我发现它不完整。
zipWithIndex()
返回Tuple
(Row, Long)
,其中包含每一行和相应的索引。我们可以根据需要使用它来创建新的Row
。
val rdd = df.rdd.zipWithIndex()
.map(indexedRow => Row.fromSeq(indexedRow._2.toString +: indexedRow._1.toSeq))
val newstructure = StructType(Seq(StructField("Row number", StringType, true)).++(df.schema.fields))
sqlContext.createDataFrame(rdd, newstructure ).show
我希望这会有所帮助。
答案 3 :(得分:3)
您可以将row_number与Window function一起使用,以获取数据框中每行的不同ID。
df.withColumn("ID", row_number() over Window.orderBy("any column name in the dataframe"))
您也可以使用monotonically_increasing_id
与
df.withColumn("ID", monotonically_increasing_id())
还有一些other ways。