Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark 在Spark数据集中创建包含运行总计的列_Apache Spark_Spark Dataframe_Rdd_Apache Spark Dataset - Fatal编程技术网

Apache spark 在Spark数据集中创建包含运行总计的列

Apache spark 在Spark数据集中创建包含运行总计的列,apache-spark,spark-dataframe,rdd,apache-spark-dataset,Apache Spark,Spark Dataframe,Rdd,Apache Spark Dataset,假设我们有一个Spark数据集,它有两列,比如索引和值,按第一列(索引)排序 我们希望有一个第三列的数据集,第二列(Value)中的值的总和是连续的 有什么建议可以让我们一次通过数据就有效地做到这一点吗?或者是否有任何罐装CDF类型的功能可以用于此 如果需要,数据集可以转换为数据帧或RDD来完成任务,但它必须保持分布式数据结构。也就是说,它不能简单地收集并转换为数组或序列,并且不能使用可变变量(val,仅限var) 但它必须保持分布式数据结构 不幸的是,你所说的你想做的事在Spark中是不可能的

假设我们有一个Spark数据集,它有两列,比如索引和值,按第一列(索引)排序

我们希望有一个第三列的数据集,第二列(Value)中的值的总和是连续的

有什么建议可以让我们一次通过数据就有效地做到这一点吗?或者是否有任何罐装CDF类型的功能可以用于此

如果需要,数据集可以转换为数据帧或RDD来完成任务,但它必须保持分布式数据结构。也就是说,它不能简单地收集并转换为数组或序列,并且不能使用可变变量(
val
,仅限
var

但它必须保持分布式数据结构

不幸的是,你所说的你想做的事在Spark中是不可能的。如果您愿意将数据集重新分区到单个分区(实际上是将其整合到单个主机上),则可以轻松地编写一个函数来执行所需操作,并将递增的值保留为字段

由于Spark函数在执行时不在网络上共享状态,因此无法创建共享状态,从而使数据集完全分布

如果您愿意放宽要求,允许数据在一台主机上通过一次传递进行整合和读取,那么您可以通过将数据重新分区到单个分区并应用函数来实现。这不会将数据拉入驱动程序(将其保存在HDFS/集群中),但仍会在单个执行器上串行计算输出。例如:

package com.github.nevernaptitsa

import java.io.Serializable
import java.util

import org.apache.spark.sql.{Encoders, SparkSession}

object SparkTest {

  class RunningSum extends Function[Int, Tuple2[Int, Int]] with Serializable {
    private var runningSum = 0
    override def apply(v1: Int): Tuple2[Int, Int] = {
      runningSum+=v1
      return (v1, runningSum)
    }
  }

  def main(args: Array[String]): Unit ={
    val session = SparkSession.builder()
      .appName("runningSumTest")
      .master("local[*]")
      .getOrCreate()
    import session.implicits._
    session.createDataset(Seq(1,2,3,4,5))
      .repartition(1)
      .map(new RunningSum)
      .show(5)
    session.createDataset(Seq(1,2,3,4,5))
      .map(new RunningSum)
      .show(5)
  }

}
这里的两个语句显示不同的输出,第一个语句提供正确的输出(串行,因为调用了
重新分区(1)
),第二个语句提供错误的输出,因为结果是并行计算的

第一次陈述的结果:

+---+---+
| _1| _2|
+---+---+
|  1|  1|
|  2|  3|
|  3|  6|
|  4| 10|
|  5| 15|
+---+---+
+---+---+
| _1| _2|
+---+---+
|  1|  1|
|  2|  2|
|  3|  3|
|  4|  4|
|  5|  9|
+---+---+
第二项声明的结果:

+---+---+
| _1| _2|
+---+---+
|  1|  1|
|  2|  3|
|  3|  6|
|  4| 10|
|  5| 15|
+---+---+
+---+---+
| _1| _2|
+---+---+
|  1|  1|
|  2|  2|
|  3|  3|
|  4|  4|
|  5|  9|
+---+---+

一位同事根据该方法提出了以下建议。 (据我所知,其他数据结构不提供对其分区索引的此类引用。)


谢谢你的详细答复,@Ed。我也这么怀疑。也许我应该为这个用例研究一种近似方法。没问题@BahmanEngheta!如果你对我的回答满意,你介意把它标为接受吗?
val data = sc.parallelize((1 to 5))  // sc is the SparkContext
val partialSums = data.mapPartitionsWithIndex{ (i, values) => 
    Iterator((i, values.sum))
}.collect().toMap  // will in general have size other than data.count
val cumSums = data.mapPartitionsWithIndex{ (i, values) => 
    val prevSums = (0 until i).map(partialSums).sum
    values.scanLeft(prevSums)(_+_).drop(1)
}