Tengo poca idea de Spark, eso es dato, pero también es cierto que estoy empezando a meterme en este tipo de tecnologías cada vez más, y lo primero, es saber cómo instalarlo, para luego poder empezar a jugar. He estado googleando y he visto bastante información, pero para una persona que no conoce muy bien este mundo, como sería mi caso (por ahora), se hace un poco confuso. En este sentido, he intentado escribir este post, con la intención de dejar una pequeña guía paso a paso, que espero que pueda ser de ayuda a más de uno. En mi caso de ejemplo, he conseguido dejar funcionando mi equipo Windows 10 con múltiples versiones de Spark, incluyendo la última también, Spark 2.3.0. Dicho todo esto, empezamos.
Instalar Java JDK
Descargar e instalar Java JDK. En las pruebas que hemos realizado hemos utilizado el JDK 8. Quizás lo único relevante sea establecer la variable en entorno JAVA_HOME, siendo recomendable utilizar la ruta corta (podemos utilizar dir /X para averiguarla), de hecho, a ser posible instalar en una ruta que no tenga espacios en blanco. También es recomendable añadir %JAVA_HOME%bin al PATH.
Instalar Git y/o Cygwin y/o GOW (Gnu On Windows)
No es estrictamente necesario, aunque si muy recomendable, entre otros motivos porque desde el GIT Bash (o desde el Command Prompt si hemos instalado GOW o Cygwin) tendremos disponibles muchos comandos tipo Linux/Unix que podremos utilizar, por ejemplo, para descomprimir los ficheros que nos vamos a descargar de Spark (*.tgz).
Instalar Anaconda (Python) y Node.js
Instalaremos Anaconda, para partir de una distribución completa de Python. En nuestro caso de ejemplo, hemos utilizado la última versión de Anaconda, que incluye una versión de Jupyter Notebook que requiere de Node.js, motivo por el que instalamos ambas cosas. No tiene gran misterio ninguna de las dos instalaciones (descargar, instalar, y listo).
Instalar winutils.exe
No es necesario instalar y configurar Hadoop para poder instalar Spark. En su lugar podemos utilizar winutils.exe como alternativa. Descargaremos la versión de winutils.exe correspondiente a la versión de hadoop para la que ha sido construida la versión de Spark que vamos a descargar. En nuestro caso de ejemplo hemos utilizando la versión de hadoop 2.7.1:
Estableceremos las siguientes variables de entorno:
- HADOOP_HOME al directorio C:\opt\hadoop
- Añadiremos al PATH su directorio bin (C:\opt\hadoop\bin). Es en el directorio bin donde copiaremos el winutils.exe.
Desde línea de comandos, crearemos un directorio c:\tmp\hive, le estableceremos permisos, y los comprobaremos. Esta práctica es recomendada para evitar errores en la spark-shell (la shell intenta encontrar el directorio \tmp\hive)
mkdir \tmp\hive winutils.exe chmod -R 777 C:\tmp\hive winutils.exe ls -F \tmp\hive |
Aunque ahora estará la carpeta vacía, cuando empecemos a utilizar Spark empezaremos a ver contenido dentro de ella, como en el siguiente ejemplo.
Instalar Apache Spark
Descargaremos la versión de Apache Spark que deseemos probar en C:\opt\spark y la descomprimiremos, por ejemplo utilizando los siguientes comandos. En nuestro caso de ejemplo hemos utilizado varias versiones de Spark, como por ejemplo la 2.1.0:
gzip -d spark-2.1.0-bin-hadoop2.7.tgz tar xvf spark-2.1.0-bin-hadoop2.7.tar |
Esto creará una carpeta C:\opt\spark\spark-2.1.0-bin-hadoop2.7. Seguidamente, estableceremos las siguientes variables de entorno (SPARK_HOME y PATH dependerá de los directorios que utilicemos):
- SPARK_HOME al directorio C:\opt\spark\spark-2.1.0-bin-hadoop2.7
- PATH añadir directorio C:\opt\spark\spark-2.1.0-bin-hadoop2.7\bin
Adicionalmente también estableceremos las siguiente variables de entorno, las cuales nos permitirán que al ejecutar el comando pyspark se abra automáticamente un Notebook de Jupyter.
- PYSPARK_DRIVER_PYTHON al valor jupyter
- PYSPARK_DRIVER_PYTHON_OPTS al valor notebook
Como alternativa, también podemos establecer la variable PYSPARK_DRIVER_PYTHON al valor ipython, para que al ejecutar el comando pyspark se abra una shell IPython (en lugar de un Notebook IPython) en la cual podamos utilizar PySpark desde línea de comandos. En nuestro caso de ejemplo, utilizaremos la configuración del Jupyter Notebook.
Por otro lado, si lo deseamos podemos instalar múltiples versiones de Apache Spark sobre diferentes directorios, de tal modo, que estableciendo las variables de entorno a la ruta correspondiente de la versión de Spark que deseamos utilizar, podamos usar la versión de Spark que necesitemos en cada caso.
Por último, antes de continuar, copiaremos el fichero de configuración log4j.properties.template del directorio C:\opt\spark\spark-2.3.0-bin-hadoop2.7\conf en el mismo directorio pero con el nombre log4j.properties, y lo editaremos, cambiando la línea:
log4j.rootCategory=INFO, console |
Por la siguiente.
log4j.rootCategory=ERROR, console |
De este modo, minimizaremos los mensajes enviados a consola (sólo se registrarán los errores), por ejemplo cuando ejecutamos programas Spark desde línea de comandos.
Crear Entornos Virtuales de Python con Conda
Crearemos los siguientes Cntornos Virtuales de Python con Conda, que consideremos en cada caso. Por ejemplo, podríamos crear uno para cada versión Python que deseemos utilizar.
conda env list conda create -n guille27-jupyter python=2.7 ipykernel conda create -n guille35-jupyter python=3.5 ipykernel conda create -n guille36-jupyter python=3.6 ipykernel |
Si quisiéramos comprobar las librerías instaladas en un virtual environment:
Si quisiéramos eliminar un virtual environmet:
conda env remove -n guille27 |
Crear Kernels IPython
Accederemos un Entorno Virtual, y crearemos dentro de el un Kernel para Jupyter. Si hemos creado tres Entornos Virtuales con diferentes versiones de Python o de Librerías, crearemos tres Kernels, uno para cada Entorno Virtual.
jupyter kernelspec list activate guille27 conda install -c conda-forge findspark=1.1.0 conda install -c cyclus java-jdk python -m ipykernel install --user --name python27 --display-name "Python 2.7" deactivate activate guille35 conda install -c conda-forge findspark=1.1.0 conda install -c cyclus java-jdk python -m ipykernel install --user --name python35 --display-name "Python 3.5" deactivate activate guille36 conda install -c conda-forge findspark=1.1.0 conda install -c cyclus java-jdk python -m ipykernel install --user --name python36 --display-name "Python 3.6" deactivate |
Si tuviésemos que comprobar los Kernel existentes y eliminar un Kernel:
jupyter kernelspec list jupyter kernelspec uninstall python2 |
Probar la Shell de Spark (Scala)
Para probar la Shell de Spark, activaremos uno de nuestros Entornos Virtuales de Python que nos hemos creado previamente, y ejecutaremos el comando spark-shell. Seguidamente ejecutaremos algun comando de ejemplo, como el que ponemos a continuación.
activate guille36 spark-shell spark.range(1).withColumn("status", lit("All seems fine. Congratulations!")).show(false) |
Deberíamos obtener una salida similar a la siguiente:
También podremos acceder con un navegador al Spark context Web UI, como se puede ver en la siguiente imagen. Para salir de la shell de Spark teclearemos :quit siendo también muy útil el comando :help
Abrir un Jupyter Notebook y probar PySpark
Para abrir un Jupyter Notebook y probar PySpark, activaremos uno de los Entornos Virtuales de Python que nos hemos creado previamente (y para los que nos hemos creado un Kernel de Jupyter), y seguidamente ejecutaremos el comando pyspark. Al haber configurado antes las variables de entorno PYSPARK_DRIVER_PYTHON y PYSPARK_DRIVER_PYTHON_OPTS a los valores jupyter y notebook respectivamente, conseguimos que al ejecutar el comando pyspark se abra un Notebook de Jupyter.
Crearemos un nuevo Notebook, con varias celdas para probar el funcionamiento de Spark.
import findspark findspark.init() import pyspark import random |
num_samples = 100000 def inside(p): x, y = random.random(), random.random() return x*x + y*y < 1 count = sc.parallelize(range(0, num_samples)).filter(inside).count() pi = 4 * count / num_samples print(pi) |
rdd = sc.parallelize(range(1, 10000000)) rdd.map(lambda x: x+1).collect() |
spark = pyspark.sql.SparkSession.builder.appName('test').getOrCreate() spark.range(10).collect() |
from pyspark.sql import SparkSession spark = SparkSession.builder.getOrCreate()
df = spark.sql('''select 'spark' as hello ''') df.show() |
file = sc.textFile("C:/temp/derby.log") words = file.flatMap(lambda line: line.split(" ")) words.count() |
A continuación se muestra un ejemplo con Spark 2.3.0 y Python 3.6 sobre Windows 10.
El comando pyspark admite diferentes parámetros. Un caso de ejemplo sería pyspark --version para poder ver la versión que estamos utilizando de Spark.
Probar PySpark desde IPython
También es posible probar PySpark desde IPython. Por ejemplo, Podemos establecer la variable PYSPARK_DRIVER_PYTHON al valor ipython, para que al ejecutar el comando pyspark se abra una shell IPython (en lugar de un Notebook IPython) en el cual podamos utilizar PySpark desde línea de comandos, tal y como se muestra en el siguiente ejemplo.
Ejecutar PySpark desde consola con spark-submit
Otra prueba que podemos hacer es ejecutar un programa Spark desde consola utilizando spark-submit. Para nuestro ejemplo vamos a preparar un pequeño código Python que cuenta las líneas de un fichero, y muestra por pantalla el número de líneas. Para ello, podemos crearnos un fichero test-spark-py con un contenido como el siguiente (necesitaremos crear explícitamente el contexto y configuración de Spark, como se ve en las tres primeras líneas):
from pyspark import SparkConf, SparkContext conf = SparkConf().setMaster("local").setAppName("TestSpark") sc = SparkContext(conf = conf) rdd = sc.textFile("C:/Users/groldan/derby.log") result = rdd.count() print(result) |
Seguidamente, lo ejecutaremos desde el Prompt de Anaconda, tal y como se muestra en la siguiente pantalla capturada.
Despedida y Cierre
Hasta aquí llega el presente artículo, en el cual hemos visto paso a paso como crearnos un entorno Spark con Jupyter Notebook en Standalone sobre Windows, ideal como entorno de pruebas y desarrollo (en muchos casos nuestras estaciones de trabajo son Windows).
Antes de finalizar, aprovecho para compartir varios enlaces de interés, para quién desee ampliar información.
Poco más por hoy. Como siempre, confío que la lectura resulte de interés.