我需要迭代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。
答案 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()
来收集数据分区:
返回包含此数据集中所有行的迭代器。该 迭代器将占用与此中最大分区一样多的内存 数据集