Spark Pipe示例

时间:2014-11-25 17:55:00

标签: scala streaming pipe apache-spark

我是Spark的新手并试图找出管道方法的工作原理。我在Scala中有以下代码

sc.textFile(hdfsLocation).pipe("preprocess.py").saveAsTextFile(hdfsPreprocessedLocation)

值hdfsLocation和hdfsPreprocessedLocation很好。作为证明,以下代码适用于命令行

hadoop fs -cat hdfsLocation/* | ./preprocess.py | head

当我运行上面的Spark代码时,我收到以下错误

14/11/25 09:41:50 ERROR Executor: Exception in task 0.0 in stage 0.0 (TID 0)
java.io.IOException: Cannot run program "preprocess.py": error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1041)
at org.apache.spark.rdd.PipedRDD.compute(PipedRDD.scala:119)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:262)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:229)
at org.apache.spark.rdd.MappedRDD.compute(MappedRDD.scala:31)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:262)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:229)
at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:62)
at org.apache.spark.scheduler.Task.run(Task.scala:54)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:177)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caused by: java.io.IOException: error=2, No such file or directory
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.<init>(UNIXProcess.java:135)
at java.lang.ProcessImpl.start(ProcessImpl.java:130)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1022)
... 12 more

为了解决Hadoop流的问题,我只想使用--files属性,所以我为Spark尝试了同样的事情。我使用以下命令启动Spark

bin/spark-shell --files ./preprocess.py

但是也出现了同样的错误。

我无法找到通过管道将Spark与外部流程结合使用的好例子,因此我不确定我是否正确地执行此操作。任何帮助将不胜感激。

由于

1 个答案:

答案 0 :(得分:1)

我不确定这是否是正确答案,因此我不会最终确定,但在本地和群集模式下运行spark时,文件路径似乎不同。在没有--master的情况下运行spark时,管道命令的路径是相对于本地机器的。使用--master运行spark时,管道命令的路径为./

更新: 这实际上是不正确的。我使用SparkFiles.get()来获取文件名。事实证明,在RDD上调用.pipe()时,会在驱动程序上评估命令字符串,然后将其传递给worker。因为这个SparkFiles.get()不是获取文件名的适当方法。文件名应为./,因为SparkContext.addFile()应将该文件放在./相对于每个工作程序的运行位置。但是我现在对.pipe非常厌恶,因为我总是将.pipe从我的代码中取出来支持.mapPartitions并结合我写的here的PipeUtils对象。这实际上更有效,因为我只需要为每个分区产生一次脚本启动成本,而不是每个示例一次。