--pyspark中的files选项不起作用



我从命令行尝试了sc.addFile选项(工作时没有任何问题)和--files选项(失败)。

运行1:spark_distro.py

from pyspark import SparkContext, SparkConf
from pyspark import SparkFiles
def import_my_special_package(x):
from external_package import external
ext = external()
return ext.fun(x)
conf = SparkConf().setAppName("Using External Library")
sc = SparkContext(conf=conf)
sc.addFile("/local-path/readme.txt")
with open(SparkFiles.get('readme.txt')) as test_file:
lines = [line.strip() for line in test_file]
print(lines)
int_rdd = sc.parallelize([1, 2, 4, 3])
mod_rdd = sorted(int_rdd.filter(lambda z: z%2 == 1).map(lambda x:import_my_special_package(x)))

外部包:external_package.py

class external(object):
def __init__(self):
pass
def fun(self,input):
return input*2

readme.txt

MY TEXT HERE

火花提交命令

spark-submit 
--master yarn-client 
--py-files /path to local codelib/external_package.py  
/local-pgm-path/spark_distro.py  
1000

输出:按预期工作

['MY TEXT HERE']

但是,如果我尝试使用--files(而不是sc.addFile)选项从命令行传递文件(readme.txt),则会失败。如下图所示。

运行2:spark_distro.py

from pyspark import SparkContext, SparkConf
from pyspark import SparkFiles
def import_my_special_package(x):
from external_package import external
ext = external()
return ext.fun(x)
conf = SparkConf().setAppName("Using External Library")
sc = SparkContext(conf=conf)
with open(SparkFiles.get('readme.txt')) as test_file:
lines = [line.strip() for line in test_file]
print(lines)
int_rdd = sc.parallelize([1, 2, 4, 3])
mod_rdd = sorted(int_rdd.filter(lambda z: z%2 == 1).map(lambda x: import_my_special_package(x)))

external_package.py与上述相同

火花提交

spark-submit 
--master yarn-client 
--py-files /path to local codelib/external_package.py  
--files /local-path/readme.txt#readme.txt  
/local-pgm-path/spark_distro.py  
1000

输出:

Traceback (most recent call last):
File "/local-pgm-path/spark_distro.py", line 31, in <module>
with open(SparkFiles.get('readme.txt')) as test_file:
IOError: [Errno 2] No such file or directory: u'/tmp/spark-42dff0d7-c52f-46a8-8323-08bccb412cd6/userFiles-8bd16297-1291-4a37-b080-bbc3836cb512/readme.txt'

sc.addFile--file的用途是否相同?有人能分享你的想法吗。

我终于解决了这个问题,这确实是一个非常微妙的问题。

正如所怀疑的那样,两个选项(sc.addFile--files)是而不是等价的,这(诚然非常微妙)暗示在文档中(强调部分增加):

addFile(路径,递归=False)
在每个节点上添加一个要使用此Spark作业下载的文件

--filesFILES
要放置在工作中的以逗号分隔的文件列表每个执行器的目录

简单地说,虽然添加了sc.addFile的文件对执行器和驱动程序都可用,但添加了--files的文件仅对执行器可用;因此,当试图从驱动程序访问它们时(就像OP中的情况一样),我们会得到一个No such file or directory错误。

让我们确认一下(去掉OP中所有不相关的--py-files1000):

test_fail.py

from pyspark import SparkContext, SparkConf
from pyspark import SparkFiles
conf = SparkConf().setAppName("Use External File")
sc = SparkContext(conf=conf)
with open(SparkFiles.get('readme.txt')) as test_file:  
lines = [line.strip() for line in test_file]
print(lines)

测试:

spark-submit --master yarn 
--deploy-mode client 
--files /home/ctsats/readme.txt 
/home/ctsats/scripts/SO/test_fail.py

结果:

[...]
17/11/10 15:05:39 INFO yarn.Client: Uploading resource file:/home/ctsats/readme.txt -> hdfs://host-hd-01.corp.nodalpoint.com:8020/user/ctsats/.sparkStaging/application_1507295423401_0047/readme.txt
[...]
Traceback (most recent call last):
File "/home/ctsats/scripts/SO/test_fail.py", line 6, in <module>
with open(SparkFiles.get('readme.txt')) as test_file:
IOError: [Errno 2] No such file or directory: u'/tmp/spark-8715b4d9-a23b-4002-a1f0-63a1e9d3e00e/userFiles-60053a41-472e-4844-a587-6d10ed769e1a/readme.txt'

在上面的脚本test_fail.py中,请求访问文件readme.txt的是驱动程序;让我们更改脚本,以便请求执行器(test_success.py)的访问:

from pyspark import SparkContext, SparkConf
conf = SparkConf().setAppName("Use External File")
sc = SparkContext(conf=conf)
lines = sc.textFile("readme.txt") # run in the executors
print(lines.collect())

测试:

spark-submit --master yarn 
--deploy-mode client 
--files /home/ctsats/readme.txt 
/home/ctsats/scripts/SO/test_success.py

结果:

[...]
17/11/10 15:16:05 INFO yarn.Client: Uploading resource file:/home/ctsats/readme.txt -> hdfs://host-hd-01.corp.nodalpoint.com:8020/user/ctsats/.sparkStaging/application_1507295423401_0049/readme.txt
[...]
[u'MY TEXT HERE']

还要注意,这里我们不需要SparkFiles.get——该文件很容易访问。

如上所述,sc.addFile将在这两种情况下都起作用,即当驱动程序或执行器请求访问时(已测试,但此处未显示)。

关于命令行选项的顺序:正如我在其他地方所说的,所有与Spark相关的参数都必须在要执行的脚本之前;可以说,--files--py-files的相对顺序是不相关的(将其作为练习)。

使用Spark 1.6.0&2.2.0.

UPDATE(在评论之后):似乎我的fs.defaultFS设置也指向HDFS:

$ hdfs getconf -confKey fs.defaultFS
hdfs://host-hd-01.corp.nodalpoint.com:8020

但让我把重点放在这里的森林(而不是树木)上,并解释为什么整个讨论只对学术感兴趣

使用--files标志传递要处理的文件是不好的做法;事后看来,我现在明白了为什么我在网上几乎找不到使用参考资料——可能没有人在实践中使用它,而且有充分的理由。

(请注意,我说的不是--py-files,它扮演着不同的合法角色。)

由于Spark是一个分布式处理框架,在集群和分布式文件系统(HDFS)上运行,因此最好的做法是将所有要处理的文件都放入HDFS中-perio。Spark处理文件的"自然"位置是HDFS,而不是本地FS——尽管有一些玩具示例仅出于演示目的使用本地FS。更重要的是,如果您希望将来有一段时间将部署模式更改为cluster,您会发现默认情况下,集群对本地路径和文件一无所知,因此…

相关内容

  • 没有找到相关文章

最新更新