如何迭代Spark的DataFrame行?

时间:2018-01-08 11:23:41

标签: scala apache-spark dataframe iterator

我需要迭代DataFrame行。

我不想将其转换为RDD并每次过滤所需的行,例如:

var index = 0
def next = {
 val result = df.rdd.filter(_._2 == index).collect.map(_._1).headOption
 index += 1
 result
}

可以选择拨打"收集"将返回Array [Row]并迭代它的方法,但我相信在拥有大量数据时它不会成​​立。

val rowsIterator:Iterator[Row] = df.collect().iterator
rowsIterator.next

更新 : 我被要求提供更多信息: 我希望将每一行写入我的数据库(在我的情况下为ES),但我没有为了使系统更稳定而使用backpresure。

1 个答案:

答案 0 :(得分:2)

嗯,你可以这样做:

val df = ss.range(10000).toDF("i")

val dfEnumerated = df
      .withColumn("row_number", row_number().over(Window.orderBy(lit(1))))
      .cache()

val collectRnb = (rnb:Int) => dfEnumerated.where($"rnb"===rnb).drop($"rnb").collect.headOption.map(_.getLong(0))
val records : Iterator[Option[Long]] = Iterator.from(1).map(collectRnb)

def next = records.next

但是在处理非常大的数据集时这也会产生问题,因为我使用了窗口函数(row_number)而没有指定分区,因此这不能很好地扩展。

您还可以使用不同方法的组合,例如一次收集1个分区并遍历此数组。

编辑:

从Spark 2.0开始,您可以使用.toLocalIterator()来收集数据分区:

  

返回包含此数据集中所有行的迭代器。该   迭代器将占用与此中最大分区一样多的内存   数据集