Scala:在列中的值满足条件时处理数据框

时间:2019-03-07 09:04:02

标签: scala apache-spark dataframe while-loop do-while

我必须处理一个巨大的数据框,并通过该数据框的id列从服务中下载文件。下载的逻辑以及所有更改已准备就绪,但是我不确定围绕此循环的最佳方法是什么。我在 Databricks 上运行它,这就是为什么我需要分块执行这些过程的原因。

数据框具有“ 状态”列,其中可以包含以下值:

  

“待办事项”,“处理”,“失败”,“成功”

在while循环中,我要执行以下任务:

while (there are rows with status "todo") {
   - get the first 10 rows if status is todo (DONE)
   - start processing the dataframe, update status to processing (DONE)
   - download files (call UDF), update status to succeeded or failed
     (DONE, not in the code here)
}

我要运行此,直到所有行中的status都不是todo !问题在于,while循环尚未完成,因为数据帧本身未更新。需要将其分配给另一个数据帧,但是如何将新的数据帧添加到循环中?

我现在的代码:

while(statusDoc.where("status == 'todo'").count > 0) {
  val todoDF = test.filter("status == 'todo'")

  val processingDF = todoDF.limit(10).withColumn("status", when(col("status") === "todo", "processing")
                           .otherwise(col("status")))

 statusDoc.join(processingDF, Seq("id"), "outer")
      .select($"id", \
       statusDoc("fileUrl"), \
       coalesce(processingDF("status"), statusDoc("status")).alias("status"))

}

联接应如下所示:

val update = statusDoc.join(processingDF, Seq("id"), "outer")
                          .select($"id", statusDoc("fileUrl"),\
    coalesce(processingDF("status"), statusDoc("status")).alias("status"))

然后,此新的update数据帧应用于下一轮循环。

1 个答案:

答案 0 :(得分:1)

这里要记住的一件事是DataFrame(Spark)不可更改,因为它们是分布式的。如果您进行了某些修改,则不能保证给定的修改会在所有执行者网络中正确传播。而且,您也不能保证数据的给定部分尚未在其他地方(例如在另一个节点中)使用。

您可以做的一件事是添加另一列具有更新后的值,然后删除旧列。

val update = statusDoc.
    .withColumnRenamed("status", "status_doc")
    .join(processingDF, Seq("id"), "outer")
    .withColumn("updated_status", udf((stold: String, stold: String) => if (stnew != null) stnew else stold).apply(col("status"), col("status_doc"))
    .drop("status_doc", "status")
    .withColumnRenamed("updated_status", "status")
    .select("id", "fileUrl", "status")

然后确保将“ statusDoc”替换为“ update” DataFrame。不要忘记将DataFrame设为“ var”,而不是“ val”。我很惊讶您的IDE还没有大喊大叫。

此外,我确定您可以想到一种分发问题的方式,从而避免了while循环-我可以为您提供帮助,但是我需要更清晰地描述您的问题。如果使用while循环,则不会使用群集的全部功能,因为while循环仅在主服务器上执行。然后,您一次只能处理10条线。我确定您可以通过一次映射操作将所需的所有数据附加到整个DataFrame中。