如何用Scala中给定数据帧的内容构造字符串

如何用Scala中给定数据帧的内容构造字符串,scala,apache-spark,spark-dataframe,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.06402005

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

考虑一下,我尝试使用下面的示例代码来实现这一点

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中为给定的
数据帧
检索字符串


非常感谢

UPD:正如@user8371915所提到的,下面的解决方案将只在开发中的单个JVM中工作(本地)。事实上,我们不能修改像globals这样的广播变量。你可以使用累加器,但效率很低。您还可以阅读关于读/写全局变量的答案。希望它能帮助你

我认为你们应该阅读Spark中关于共享变量的主题

通常,当传递给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))

希望这有帮助。

df.show(false)的输出有帮助吗?如果是,那么这个答案会有帮助:

感谢大家的反馈,感谢大家对这一点的理解

这些回答的组合结果如下所示。由于我将df表示为JSON列表,因此需求略有变化。下面的代码在不使用广播的情况下执行此操作

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

这样的操作真的没有多大用处。当然,您可以,
df.collect.map(u.toString).mkString(“,”)
,但它当然不会缩放。而
df
RDD
不是
DataFrame
。类似于
df.show()
的字符串怎么样?你能详细说明一下这个答案的要点吗?如果您试图证明广播变量可以用作写入的共享变量,那么这是完全错误的。它之所以有效,是因为您在开发(本地)模式下使用单个JVM:是的。你完全正确。那是我的错误。我们不能这样使用它们。第一部分你是对的。请随意修改我的评论()以提供解决方案。您也可以使用累加器(),但它效率低下,而且会带来一些额外的问题。请@me,一旦你纠正了这一点,我将收回我的投票。@user8371915我已经添加了顶部带有更新的部分。谢谢你的澄清。