J'ai un problème avec l'utilisation de Python sur Spark. Mon application a des dépendances, telles que numpy, pandas, astropy, etc. Je ne peux pas utiliser virtualenv pour créer un environnement avec toutes les dépendances, car les nœuds du cluster n'ont pas de point de montage ou de système de fichiers commun, à l'exception de HDFS. Par conséquent, je suis coincé avec spark-submit --py-files
. Je compresse le contenu des packages de site dans un fichier Zip et soumet le travail avec l'option --py-files=dependencies.Zip
(comme indiqué dans Le moyen le plus simple d'installer des dépendances Python sur des nœuds d'exécuteur Spark? ). Cependant, les nœuds du cluster ne semblent toujours pas voir les modules à l'intérieur et ils jettent ImportError
comme celui-ci lors de l'importation de numpy.
File "/path/anonymized/module.py", line 6, in <module>
import numpy
File "/tmp/pip-build-4fjFLQ/numpy/numpy/__init__.py", line 180, in <module>
File "/tmp/pip-build-4fjFLQ/numpy/numpy/add_newdocs.py", line 13, in <module>
File "/tmp/pip-build-4fjFLQ/numpy/numpy/lib/__init__.py", line 8, in <module>
#
File "/tmp/pip-build-4fjFLQ/numpy/numpy/lib/type_check.py", line 11, in <module>
File "/tmp/pip-build-4fjFLQ/numpy/numpy/core/__init__.py", line 14, in <module>
ImportError: cannot import name multiarray
Lorsque je passe à virtualenv et utilise le shell local pyspark, tout fonctionne correctement et toutes les dépendances sont présentes. Est-ce que quelqu'un sait ce qui pourrait causer ce problème et comment le résoudre?
Merci!
Tout d'abord, je suppose que vos dépendances sont listées dans requirements.txt
. Pour empaqueter et décompresser les dépendances, exécutez ce qui suit sur la ligne de commande:
pip install -t dependencies -r requirements.txt
cd dependencies
Zip -r ../dependencies.Zip .
Ci-dessus, la commande cd dependencies
est cruciale pour garantir que les modules se trouvent au plus haut niveau du fichier Zip. Merci à le message de Dan Corin pour le heads up.
Ensuite, soumettez le travail via:
spark-submit --py-files dependencies.Zip spark_job.py
La directive --py-files
envoie le fichier Zip aux employés Spark mais ne l’ajoute pas à la PYTHONPATH
(source de confusion pour moi). Pour ajouter les dépendances à la PYTHONPATH
afin de corriger la ImportError
, ajoutez la ligne suivante au travail Spark, spark_job.py
:
sc.addPyFile("dependencies.Zip")
Un avertissement de ce post de Cloudera :
Une hypothèse selon laquelle quiconque fait de l'informatique distribuée avec commodité Le matériel doit supposer que le matériel sous-jacent est potentiellement hétérogène. Un œuf Python construit sur un ordinateur client sera spécifique l’architecture de la CPU du client en raison de la nécessité de C compilation. Distribuer un oeuf pour un package complexe et compilé tel que NumPy, SciPy ou pandas est une solution fragile susceptible d’échouer sur la plupart des grappes, du moins éventuellement.
Bien que la solution ci-dessus ne construise pas d'œuf, la même directive s'applique.
Spark ne pourra également pas charger silencieusement une archive Zip créée avec le module python zipfile
. Les archives Zip doivent être créées à l'aide d'un utilitaire Zip.
Vous pouvez localiser tous les fichiers .pys dont vous avez besoin et les ajouter relativement . Voir ici pour cette explication:
import os, sys, inspect
# realpath() will make your script run, even if you symlink it :)
cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
if cmd_folder not in sys.path:
sys.path.insert(0, cmd_folder)
# use this if you want to include modules from a subfolder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"subfolder")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
# Info:
# cmd_folder = os.path.dirname(os.path.abspath(__file__)) # DO NOT USE __file__ !!!
# __file__ fails if script is called in different ways on Windows
# __file__ fails if someone does os.chdir() before
# sys.argv[0] also fails because it doesn't not always contains the path