私は試した 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コマンド
spark-submit \
--master yarn-client \
--py-files /path to local codelib/external_package.py \
/local-pgm-path/spark_distro.py \
1000
出力:期待どおりに機能しています
['MY TEXT HERE']
しかし、(sc.addFileの代わりに)-filesオプションを使用してコマンドラインからファイル(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
同じ目的で使用されますか?誰かがあなたの考えを共有できますか?.
私はついに問題を理解しました、そしてそれは確かに非常に微妙な 1つです。
疑われるように、2つのオプション(sc.addFile
と--files
)は等しくないであり、これは(確かに非常に微妙に)示唆されていますドキュメントで(強調を追加):
addFile
(path、recursive = False)
このSparkジョブをすべてのノードでダウンロードするファイルを追加します。
--files
ファイル
各エグゼキュータの作業ディレクトリに配置されるファイルのコンマ区切りリスト。
平易な英語では、sc.addFile
で追加されたファイルはエグゼキュータとドライバの両方で使用できますが、--files
で追加されたファイルはエグゼキュータでのみ使用できます。したがって、(OPの場合のように)ドライバーからそれらにアクセスしようとすると、No such file or directory
エラーが発生します。
これを確認しましょう(OP内の無関係な--py-files
および1000
のものをすべて削除します):
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
へのアクセスを要求するのはdriverプログラムです。スクリプトを変更して、executors(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
はどちらの場合でも機能します。つまり、アクセスがドライバーまたはエグゼキューターのいずれかによって要求された場合です(テスト済みですが、ここには示されていません)。
コマンドラインオプションの順序について:私が議論したように elsewhere 、すべての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に処理することです--- 期間。ファイルが処理される「自然な」場所SparkはHDFSであり、ローカルではありませんFS-いくつかありますがtoyローカルFSをデモンストレーション目的でのみ使用した例。さらに、将来的に時間が必要な場合は、デプロイモードをcluster
に変更すると、クラスターはデフォルトでローカルパスとファイルを認識していないことがわかります。当然のことながら...