如何检查DataFrames?

时间:2015-10-29 20:56:42

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

我正在寻找一种检查点DataFrames的方法。 Checkpoint目前是RDD上的一个操作,但我找不到如何使用DataFrames。持久化和缓存(它们是彼此的同义词)可用于DataFrame,但它们不会“打破血统”,因此不适用于可循环数百(或数千)次迭代的方法。

例如,假设我有一个其签名为DataFrame =>的函数列表。数据帧。即使myfunctions有数百或数千个条目,我想有办法计算以下内容:

def foo(dataset: DataFrame, g: DataFrame => Unit) =
    myfunctions.foldLeft(dataset) {
        case (df, f) =>
            val nextDF = f(df)
            g(nextDF)
            nextDF
   }

5 个答案:

答案 0 :(得分:20)

TL; DR:对于高达1.6的Spark版本,要实际获得"检查点DF",我建议的解决方案基于另一个答案,但有一个额外的行:

df.rdd.checkpoint
df.rdd.count
val df2 = sqlContext.createDataFrame(df.rdd, df.schema)
// df2 is checkpointed

<强>解释

经过进一步研究后更新。

正如所指出的,直接检查DataFrame当前不是(Spark 1.6.1),尽管Spark的Jira上有issue

因此,可能的解决方法是在另一个答案中提出的建议:

df.rdd.checkpoint // Assuming the checkpoint dir has already been set
df.count // An action to compute the checkpoint

但是,使用此方法,只会检查df.rdd对象。这可以通过致电toDebugStringdf.rdd来验证:

 scala> df.rdd.toDebugString
 (32) MapPartitionsRDD[1] at rdd at <console>:38 []
  |   ReliableCheckpointRDD[2] at count at <console>:38 []

然后在快速转换为toDebugString之后调用df(请注意我从JDBC源创建了我的DataFrame),返回以下内容:

scala> df.withColumn("new_column", lit(0)).rdd.toDebugString
res4: String =
(32) MapPartitionsRDD[5] at rdd at <console>:38 []
 |   MapPartitionsRDD[4] at rdd at <console>:38 []
 |   JDBCRDD[3] at rdd at <console>:38 []

df.explain也会显示提示:

scala> df.explain
== Physical Plan ==
Scan JDBCRelation (...)

所以,要真正实现&#34;检查点&#34; DataFrame,我只能想到从检查点RDD创建一个新的:

val newDF = sqlContext.createDataFrame(df.rdd, df.schema)
// or
val newDF = df.rdd.map { 
  case Row(val1: Int, ..., valN: Int) => (val1, ..., valN)
}.toDF("col1", ..., "colN")

然后我们可以验证新的DataFrame是否为&#34;检查点&#34;:

1)newDF.explain

scala> newDF.explain
== Physical Plan ==
Scan PhysicalRDD[col1#5, col2#6, col3#7]

2)newDF.rdd.toDebugString

scala> newDF.rdd.toDebugString
res7: String =
(32) MapPartitionsRDD[10] at rdd at <console>:40 []
 |   MapPartitionsRDD[8] at createDataFrame at <console>:37 []
 |   MapPartitionsRDD[1] at rdd at <console>:38 []
 |   ReliableCheckpointRDD[2] at count at <console>:38 []

3)转型:

scala> newDF.withColumn("new_column", lit(0)).rdd.toDebugString
res9: String =
(32) MapPartitionsRDD[12] at rdd at <console>:40 []
 |   MapPartitionsRDD[11] at rdd at <console>:40 []
 |   MapPartitionsRDD[8] at createDataFrame at <console>:37 []
 |   MapPartitionsRDD[1] at rdd at <console>:38 []
 |   ReliableCheckpointRDD[2] at count at <console>:38 []

另外,我尝试了一些更复杂的转换,实际上,我能够检查newDF对象是否已经过检查点。

因此,我发现可靠地检查DataFrame的唯一方法是通过检查点关联的RDD并从中创建一个新的DataFrame对象。

我希望它有所帮助。欢呼声。

答案 1 :(得分:7)

从spark 2.1开始,数据帧有一个可以直接使用的检查点方法(参见http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.sql.Dataset),无需通过RDD。

答案 2 :(得分:4)

我想现在你必须要做

sc.setCheckpointDir("/DIR")
df.rdd.checkpoint

然后您必须对基础df.rdd执行操作。致电df.ACTION目前无效,仅df.rdd.ACTION

答案 3 :(得分:3)

  

延伸到Assaf Mendelson回答,

截至今日Spark版本2.2,DataSet#checkpoint() API 进化和实验

用法:

在检查点之前必须使用SparkContext

提及CheckpointDir
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_2.h>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Delaunay_triangulation_2<K>  Triangulation;
typedef Triangulation::Edge_iterator  Edge_iterator;
typedef Triangulation::Point          Point;
int main( )
{
  std::ifstream in("data/voronoi.cin");
  std::istream_iterator<Point> begin(in);
  std::istream_iterator<Point> end;
  Triangulation T;
  T.insert(begin, end);
  int ns = 0;
  int nr = 0;
  Edge_iterator eit =T.edges_begin();
  for ( ; eit !=T.edges_end(); ++eit) {
    CGAL::Object o = T.dual(eit);
    if (CGAL::object_cast<K::Segment_2>(&o)) {++ns;}
    else if (CGAL::object_cast<K::Ray_2>(&o)) {++nr;}
  }
  std::cout << "The Voronoi diagram has " << ns << " finite edges "
        << " and " << nr << " rays" << std::endl;
  return 0;
}

内部如何运作?

到目前为止,implementation for DataSet checkpoint是将DataSet转换为RDD然后检查它。

spark.sparkContext.setCheckpointDir("checkpoint/dir/location")

val ds: Dataset[Long] = spark.range(10).repartition('id % 2)

// do checkpoint now, it will preserve partition also
val cp: Dataset[Long] = ds.checkpoint()

答案 4 :(得分:1)

最初的问题是关于Scala Spark的,但是我认为添加PySpark语法也很有用,这非常相似。请注意,与cache / persist不同的是,checkpoint不能就地运行(最初使我绊倒了):

spark.sparkContext.setCheckpointDir("/foo/bar")
df = df.checkpoint()