如何在Scala中使用给定DataFrame的内容构造String

时间:2018-01-15 18:57:38

标签: scala apache-spark spark-dataframe

考虑我有一个数据帧。如何检索该数据帧的内容并将其表示为字符串。

考虑一下我尝试使用下面的示例代码。

val tvalues: Array[Double] = Array(1.866393526974307, 2.864048126935307, 4.032486069215076, 7.876169953355888, 4.875333799256043, 14.316322626848278)
val pvalues: Array[Double] = Array(0.064020056478447, 0.004808399479386827, 8.914865448939047E-5, 7.489564524121306E-13, 2.8363794106756046E-6, 0.0)

val conf = new SparkConf().setAppName("Simple Application").setMaster("local[2]");
val sc = new SparkContext(conf)
val df = sc.parallelize(tvalues zip pvalues)
val sb = StringBuilder.newBuilder
df.foreach(x => {
  println("x = ", x)
  sb.append(x)
})
println("sb = ", sb)

代码的输出显示示例数据框具有内容:

(x = ,(1.866393526974307,0.064020056478447))
(x = ,(7.876169953355888,7.489564524121306E-13))
(x = ,(2.864048126935307,0.004808399479386827))
(x = ,(4.032486069215076,8.914865448939047E-5))
(x = ,(4.875333799256043,2.8363794106756046E-6))

但是,最终的stringbuilder包含一个空字符串。

如何在Scala中检索给定dataframe的字符串?

非常感谢

3 个答案:

答案 0 :(得分:1)

UPD :如@ user8371915所述,下面的解决方案仅适用于开发中的单个JVM(本地)mode。事实上,我们无法修改像globals这样的广播变量。你可以使用累加器,但效率很低。您还可以阅读有关读/写全局变量here的答案。希望它会对你有所帮助。

我认为您应该阅读有关Spark中共享变量的主题。 Link here

  

通常,当在远程集群节点上执行传递给Spark操作(例如map或reduce)的函数时,它将在函数中使用的所有变量的单独副本上工作。这些变量将复制到每台计算机,并且远程计算机上的变量的更新不会传播回驱动程序。支持跨任务的通用,读写共享变量效率低下。但是,Spark确实为两种常见的使用模式提供了两种有限类型的共享变量:广播变量和累加器。

让我们来看看广播变量。我编辑了你的代码:

val tvalues: Array[Double] = Array(1.866393526974307, 2.864048126935307, 4.032486069215076, 7.876169953355888, 4.875333799256043, 14.316322626848278)
val pvalues: Array[Double] = Array(0.064020056478447, 0.004808399479386827, 8.914865448939047E-5, 7.489564524121306E-13, 2.8363794106756046E-6, 0.0)

val conf = new SparkConf().setAppName("Simple Application").setMaster("local[2]");
val sc = new SparkContext(conf)
val df = sc.parallelize(tvalues zip pvalues)
val sb = StringBuilder.newBuilder
val broadcastVar = sc.broadcast(sb)
df.foreach(x => {
  println("x = ", x)
  broadcastVar.value.append(x)
})
println("sb = ", broadcastVar.value)

这里我使用broadcastVar作为StringBuilder变量sb的容器。 输出结果如下:

(x = ,(1.866393526974307,0.064020056478447))
(x = ,(2.864048126935307,0.004808399479386827))
(x = ,(4.032486069215076,8.914865448939047E-5))
(x = ,(7.876169953355888,7.489564524121306E-13))
(x = ,(4.875333799256043,2.8363794106756046E-6))
(x = ,(14.316322626848278,0.0))
(sb = ,(7.876169953355888,7.489564524121306E-13)(1.866393526974307,0.064020056478447)(4.875333799256043,2.8363794106756046E-6)(2.864048126935307,0.004808399479386827)(14.316322626848278,0.0)(4.032486069215076,8.914865448939047E-5))

希望这有帮助。

答案 1 :(得分:0)

df.show(false)的输出有帮助吗?如果是,那么这个SO答案有助于:Is there any way to get the output of Spark's Dataset.show() method as a string?

答案 2 :(得分:0)

感谢大家的反馈,并对此有所了解。

响应的组合导致如下。要求略有改变,因为我将我的df表示为jsons列表。下面的代码执行此操作,不使用广播。

class HandleDf(df: DataFrame, limit: Int) extends java.io.Serializable {
  val jsons = df.limit(limit).collect.map(rowToJson(_))

  def rowToJson(r: org.apache.spark.sql.Row) : JSONObject = {
    try { JSONObject(r.getValuesMap(r.schema.fieldNames)) }
    catch { case t: Throwable =>
        JSONObject.apply(Map("Row with error" -> t.toString))
    }
  }
}

我在这里使用的课程......

val jsons = new HandleDf(df, 100).jsons