Scala collect方法存在SparkSQL性能问题
我们目前在用scala语言编写的sparksql中面临一个性能问题。应用程序流程如下所述Scala collect方法存在SparkSQL性能问题,scala,apache-spark,spark-dataframe,Scala,Apache Spark,Spark Dataframe,我们目前在用scala语言编写的sparksql中面临一个性能问题。应用程序流程如下所述 Spark应用程序从输入hdfs目录读取文本文件 使用编程方式指定架构在文件顶部创建数据框。此数据帧将是内存中保存的输入文件的精确复制。在数据帧中将有大约18列 var eqpDF=sqlContext.createDataFrame(eqpRowRdd,eqpSchema) 从步骤2中构造的第一个数据帧创建过滤后的数据帧。此数据框将在distinct关键字的帮助下包含唯一的帐号 var distAccNr
var eqpDF=sqlContext.createDataFrame(eqpRowRdd,eqpSchema)
var distAccNrsDF=eqpDF.select(“accountnumber”).distinct().collect()
var filterqpdf=
eqpDF.where(“accountnumber=”+data.getString(0)+“”).collect()
在这种情况下通常采取的方法是:
- 调用
:而不是foreachPartition
:collect
将函数分别应用于基础foreachPartition
数据帧的每个分区(由
表示)(分区是Spark并行的原子单位)迭代器[Row]
- 该函数将打开到HBase的连接(从而使每个分区都有一个连接),并通过该连接发送所有包含的值
spark.read.csv(inputPath). // Using DataFrameReader but your way works too
foreachPartition { rows =>
val conn = ??? // Create HBase connection
for (row <- rows) { // Loop over the iterator
val data = parseJson(row) // Your parsing logic
??? // Use 'conn' to save 'data'
}
}
spark.read.csv(输入路径)。//使用DataFrameReader,但您的方式也适用
foreachPartition{rows=>
val conn=???//创建HBase连接
对于(row而言,在这种情况下通常采用的方法是:
- 调用
foreachPartition
:而不是collect
:foreachPartition
将函数分别应用于基础数据帧的每个分区(由迭代器[Row]
表示)(分区是Spark并行的原子单位)
- 该函数将打开到HBase的连接(从而使每个分区都有一个连接),并通过该连接发送所有包含的值
这意味着每个执行器打开一个连接(该连接不可序列化,但位于函数的边界内,因此不需要通过网络发送),并独立地将其内容发送到HBase,而无需收集驱动程序(或任何一个节点)上的所有数据
看起来您正在读取一个CSV文件,因此可能需要执行以下操作:
spark.read.csv(inputPath). // Using DataFrameReader but your way works too
foreachPartition { rows =>
val conn = ??? // Create HBase connection
for (row <- rows) { // Loop over the iterator
val data = parseJson(row) // Your parsing logic
??? // Use 'conn' to save 'data'
}
}
spark.read.csv(inputPath)。//使用DataFrameReader,但您的方式也可以
foreachPartition{rows=>
val conn=???//创建HBase连接
对于(row),如果有大量数据,可以忽略代码中的collect
Collect在驱动程序中以数组形式返回数据集的所有元素。这通常在执行筛选器或其他返回足够小的数据子集的操作后非常有用
不过,这也可能导致驱动程序内存不足,因为collect()将整个RDD/DF提取到一台机器上
我刚刚编辑了你的代码,应该适合你
var distAccNrsDF = eqpDF.select("accountnumber").distinct()
distAccNrsDF.foreach { data =>
var filtrEqpDF = eqpDF.where("accountnumber='" + data.getString(0) + "'")
var result = new JSONObject()
result.put("jsonSchemaVersion", "1.0")
val firstRowAcc = filtrEqpDF(0)
//Json parsing logic
{
.....
.....
}
}
如果有大量数据,则可以忽略代码中的collect
Collect在驱动程序中以数组形式返回数据集的所有元素。这通常在执行筛选器或其他返回足够小的数据子集的操作后非常有用
不过,这也可能导致驱动程序内存不足,因为collect()将整个RDD/DF提取到一台机器上
我刚刚编辑了你的代码,应该适合你
var distAccNrsDF = eqpDF.select("accountnumber").distinct()
distAccNrsDF.foreach { data =>
var filtrEqpDF = eqpDF.where("accountnumber='" + data.getString(0) + "'")
var result = new JSONObject()
result.put("jsonSchemaVersion", "1.0")
val firstRowAcc = filtrEqpDF(0)
//Json parsing logic
{
.....
.....
}
}
您实际上想要做什么?只需写入Hbase表?如果是这样,为什么要收集或获取?收集和获取仅用于查看样本数据。除此之外,不需要使用收集或获取。基本上,我们需要将属于同一帐号的所有数据分组(在源文件中)并且分组的数据必须推送到hbase。我们使用Collect是因为,为了全局查找不同的帐号。如果我们不调用Collect,我们如何全局查找可能分布在多个节点中的唯一帐号。您认为呢