Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.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
Scala 将多个文件作为独立的RDD处理';平行的_Scala_Apache Spark_Apache Spark Sql - Fatal编程技术网

Scala 将多个文件作为独立的RDD处理';平行的

Scala 将多个文件作为独立的RDD处理';平行的,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我有一个场景,其中包括GROUPBY在内的一定数量的操作必须应用于许多小文件(每个文件约300MB)。操作看起来是这样的 df.groupBy(..).agg(..) 现在要在多个文件上处理它,我可以使用通配符“/**/*.csv”,但是,它会创建一个RDD并将其分区以用于操作。但是,从操作上看,这是一个分组操作,涉及大量的洗牌操作,如果文件相互排斥,则不必进行洗牌 我正在研究的是,我可以在文件上创建独立的RDD,并对其进行独立操作。如果您有许多文件,并且每个文件都很小(您可以说300MB以上,

我有一个场景,其中包括GROUPBY在内的一定数量的操作必须应用于许多小文件(每个文件约300MB)。操作看起来是这样的

df.groupBy(..).agg(..)

现在要在多个文件上处理它,我可以使用通配符“/**/*.csv”,但是,它会创建一个RDD并将其分区以用于操作。但是,从操作上看,这是一个分组操作,涉及大量的洗牌操作,如果文件相互排斥,则不必进行洗牌


我正在研究的是,我可以在文件上创建独立的RDD,并对其进行独立操作。

如果您有许多文件,并且每个文件都很小(您可以说300MB以上,我可以将其视为Spark的小文件),您可以尝试使用
SparkContext.wholeTextFiles
,它将创建一个RDD,其中每个记录都是一个完整的文件

这与其说是一个完整的解决方案,不如说是一个想法,我还没有测试过它

您可以从将数据处理管道提取到函数中开始

def pipeline(f: String, n: Int) = {
    sqlContext
        .read
        .format("com.databricks.spark.csv")
        .option("header", "true")
        .load(f)
        .repartition(n)
        .groupBy(...)
        .agg(...)
        .cache // Cache so we can force computation later
}
如果您的文件很小,您可以调整
n
参数以使用尽可能少的分区,以适应单个文件中的数据并避免混乱。这意味着您正在限制并发性,但我们稍后将继续讨论这个问题

val n: Int = ??? 
接下来,您必须获得输入文件的列表。此步骤取决于数据源,但大多数情况下,它或多或少是简单的:

val files: Array[String] = ???
接下来,您可以使用
管道
功能映射上述列表:

val rdds = files.map(f => pipeline(f, n))
由于我们将并发限制在单个文件的级别,因此我们希望通过提交多个作业来进行补偿。让我们添加一个简单的帮助器,它强制求值并用
Future

import scala.concurrent._
import ExecutionContext.Implicits.global

def pipelineToFuture(df: org.apache.spark.sql.DataFrame) = future {
    df.rdd.foreach(_ => ()) // Force computation
    df
}
最后,我们可以在
RDD
上使用上述帮助程序:

val result = Future.sequence(
   rdds.map(rdd => pipelineToFuture(rdd)).toList
)

根据您的需求,您可以添加
onComplete
回调或使用反应流来收集结果。

通过这种方式,我们可以并行编写多个RDD

public class ParallelWriteSevice implements IApplicationEventListener {

    private static final IprogramLogger logger = programLoggerFactory.getLogger(ParallelWriteSevice.class);

    private static ExecutorService executorService=null;
    private static List<Future<Boolean>> futures=new ArrayList<Future<Boolean>>();

    public static void submit(Callable callable) {
        if(executorService==null)
        {
            executorService=Executors.newFixedThreadPool(15);//Based on target tables increase this
        }

        futures.add(executorService.submit(callable));
    }

    public static boolean isWriteSucess() {
        boolean writeFailureOccured = false;
        try {
            for (Future<Boolean> future : futures) {
                try {
                    Boolean writeStatus = future.get();
                    if (writeStatus == false) {
                        writeFailureOccured = true;
                    }
                } catch (Exception e) {
                    logger.error("Erorr - Scdeduled write failed " + e.getMessage(), e);
                    writeFailureOccured = true;
                }
            }
        } finally {
            resetFutures();         
              if (executorService != null) 
                  executorService.shutdown();
              executorService = null;

        }
        return !writeFailureOccured;
    }

    private static void resetFutures() {
            logger.error("resetFutures called");
            //futures.clear();
    }




}
公共类ParallelWriteDevice实现IAApplicationEventListener{
私有静态最终IprogramLogger=programLoggerFactory.getLogger(parallelWriteDevice.class);
私有静态ExecutorService ExecutorService=null;
private static List futures=new ArrayList();
公共静态无效提交(可调用){
if(executorService==null)
{
executorService=Executors.newFixedThreadPool(15);//根据目标表增加此值
}
futures.add(executorService.submit(callable));
}
公共静态布尔值isWriteSucess(){
布尔writeFailureOccursed=false;
试一试{
for(未来:未来){
试一试{
布尔writeStatus=future.get();
if(writeStatus==false){
WriteFailureOccursed=true;
}
}捕获(例外e){
logger.error(“Erorr-推断写入失败”+e.getMessage(),e);
WriteFailureOccursed=true;
}
}
}最后{
重置期货();
if(executorService!=null)
executorService.shutdown();
executorService=null;
}
return!发生writefailured;
}
私有静态void resetFutures(){
logger.error(“resetFutures”);
//期货;
}
}

嗯,就我而言,没有必要采取变通办法,因为这在这里完全无关紧要
sqlContext
只在驱动程序上使用,因此没有任何理由进行序列化。@Alexaspo并没有完全做到这一点,但我使用过一两次类似的方法。除非您有非常多的内存,否则执行实际操作而不是依赖缓存更有意义。如果您对一般原则感兴趣,请查看
org.apache.spark.rdd.AsyncRDDActions