Кажется, я не могу получить -py файлы на Spark для работы

У меня проблема с использованием Python на Spark. Мое приложение имеет некоторые зависимости, такие как numpy, pandas, astropy и т.д. Я не могу использовать virtualenv для создания среды со всеми зависимостями, поскольку узлы в кластере не имеют общей точки монтирования или файловой системы, кроме HDFS. Поэтому я застрял с использованием spark-submit --py-files. Я упаковываю содержимое сайтов-пакетов в ZIP файл и отправляю задание, например, с помощью параметра --py-files=dependencies.zip (как это предлагается в разделе Самый простой способ установить зависимости Python на узлы-исполнители Spark?). Тем не менее, узлы в кластере по-прежнему не видят модули внутри, и они бросают ImportError например, при импорте 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

Когда я переключаюсь на virtualenv и использую локальную оболочку pyspark, все работает нормально, поэтому все зависимости есть. Кто-нибудь знает, что может вызвать эту проблему и как ее исправить?

Благодарю!

Ответ 1

Во-первых, я буду считать, что ваши зависимости указаны в requirements.txt. requirements.txt. Чтобы упаковать и заархивировать зависимости, запустите в командной строке следующее:

pip install -t dependencies -r requirements.txt
cd dependencies
zip -r ../dependencies.zip .

Выше команда cd dependencies имеет решающее значение для обеспечения того, чтобы модули находились на верхнем уровне zip файла. Спасибо за сообщение Дэна Корина за хедз-ап.

Затем отправьте задание через:

spark-submit --py-files dependencies.zip spark_job.py

--py-files отправляет zip файл рабочим Spark, но не добавляет его в PYTHONPATH (источник путаницы для меня). Чтобы добавить зависимости PYTHONPATH к исправлению ImportError, добавьте следующую строку в задание spark_job.py: spark_job.py:

sc.addPyFile("dependencies.zip")

Оговорка из этого сообщения Клаудера:

Предполагается, что любой, кто делает распределенные вычисления с товарным оборудованием, должен предположить, что базовое оборудование потенциально гетерогенно. Яйцо Python, построенное на клиентской машине, будет специфично для архитектуры процессора клиентов из-за необходимой компиляции C. Распределение яйца для сложного, скомпилированного пакета, такого как NumPy, SciPy или pandas, - это хрупкое решение, которое, по крайней мере, в конечном итоге может потерпеть неудачу на большинстве кластеров.

Хотя вышеприведенное решение не создает яйцо, применяется одно и то же правило.

Ответ 2

  • Сначала вам нужно передать свои файлы через --py файлы или --files

    • Когда вы передаете свои zip файлы с указанными выше флагами, в основном ваши ресурсы будут перенесены во временный каталог, созданный на HDFS, только на время жизни этого приложения.
  • Теперь в вашем коде добавьте эти zip файлы, используя следующую команду

    sc.addPyFile("your zip/file")

    • что делает выше, он загружает файлы в среду выполнения, например JVM.
  • Теперь импортируйте свой zip/файл в свой код с псевдонимом следующим образом, чтобы начать ссылаться на него

    import zip/file as your-alias

    Примечание. Вам не нужно использовать расширение файла при импорте, например .py в конце

Надеюсь, это полезно.

Ответ 3

Вы можете найти все нужные вам.pys и добавить их относительно. см. здесь для объяснения:

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

Ответ 4

Spark также без проблем загрузит zip-архив, созданный с помощью zipfile модуля python. Zip-архивы должны быть созданы с использованием утилиты zip.