Spark Scala con Maven en IntelliJ

Este es un post que la verdad no había tenido en mente crear pero últimamente se me ha convertido en una necesidad y la verdad he disfrutado hacer y es que en estos ya casi 5 años involucrado en temas relacionados con Big Data y la nube la verdad es que he podido notar como construir un proyecto Spark desde cero se convierte en algo fácil pero netamente basado en copiar y pegar de proyectos anteriores, pero … y qué sucede cuando no hay un proyecto anterior jejeje, pero no es el único caso y qué sucede con aquellos que están aprendiendo, es cuestión de indagar por Internet y encuentras 30 formas distintas de armar un proyecto desde cero de Spark con Scala con Maven y en un IDE en este caso IntelliJ, pero cual es la idónea, cual es la que verdaderamente funciona.

Pues he decidido crear un esqueleto de proyecto (el cual espero poder ir evolucionando y mejorarlo) que seguramente no es la mejor pero desde mi humilde punto de vista es funcional.

Configurar el IDE

Lo primero antes que nada es instalar el jsdk (1.8 como mínimo), luego en la instalación o inmediatamente después es asegurarnos de contar con los plugins de Maven y Scala, para ello en la ventana de inicio vamos a los plugins.

Buscamos el plugin de Scala para verificar que este instalado si no lo está lo instalamos y luego en la misma ventana en la parte superior junto a Marketplace hacemos clic en installed y verificamos que el plugin de maven por defecto este habilitado.

Creamos el proyecto

Seleccionamos la opción de crear un nuevo proyecto.

Ventana de inicio de IntelliJ

Acto seguido seleccionamos la opción de proyecto maven y marcamos la opción de Create from archetype. Seleccionamos el archetype net.alchim31.maven:scala-archetype-simple y pulsamos el botón “Next”. Si el archetype no existe pulsamos el botón de Añadir Archetype (Add Archetype) cumplimentamos la información con los siguientes datos:
GroupId: net.alchim31.maven
ArtifactId: scala-archetype-simple
Version: 1.7

Una vez añadido lo seleccionamos y como habíamos indicado antes pulsamos el botón “Next”.

Indicamos el archetype en caso de no estar presente en la lista
Lista de archetypes para crear el proyecto

Inmediatamente después le daremos nombre a nuestro proyecto y si queremos ser más específicos indicamos el GroupId, ArtifactId y versión de nuestro proyecto (OJO esto último es opcional), pulsamos “Next” y por último en la ventana resumen pulsamos “Finish”.

Configuración de nuestro artifact

Lo primero que deberemos hacer para que nos facilite la tarea será habilitar la autoimportación de las dependencias maven como señalamos en la imagen.

Habilitamos la autoimportación de dependencias

El construir el proyecto a partir de un archetype (arquetipo) maven consiste en armar el esqueleto de un proyecto a partir de una plantilla definiendo una estructura minima por defecto, por lo cual veremos un fichero pom.xml (gestión de dependencias maven) con algunas dependencias y una estructura de carpetas para el código fuente y pruebas unitarias, con ficheros incluidos.

Estructura del proyecto reciéntame creado

Aprovechamos de dar un vistazo a la clase App y a las pruebas unitarias que por defecto nos añade al proyecto e incluso podemos compilar el proyecto para contrastar que todo está de maravilla y para ello solamente necesitamos hacer clic en la pestaña maven ubicado en la parte derecha, donde aparece el nombre de nuestro proyecto desplegar lifecycle y hacer doble clic en compile y esto iniciará el proceso de compilación terminando exitosamente.

Añadimos dependencias

Ya estamos llegando al final, ahora lo que haremos será añadir al fichero pom.xml las dependencias spark que utilizaremos para este ejemplo. Empezaremos por editar las propiedades quedando estas así:

Añadimos las dependencias de spark al conjunto de dependencias existentes

Por último modificaremos nuestra clase App quedando esta así:

Para de nuevo volver a compilar el proyecto, que deberá culminar exitosamente.

Ejecución

La forma que indicaremos para la ejecución de los jobs desde IntelliJ no es la mejor pero es una forma sencilla y funcional para probar cosas y sobre todo para quien comienza a hacer tests sin necesidad de empaquetar y crear un jar y desplegarlo en una máquina virtual o en un cluster. ¿Cuál sería entonces la mejor forma? A mi modo de ver las cosas la mejor forma sería mediante prueba unitarias y de integración donde podamos probar todo el job de inicio a fin y para explicarles como ya tengo en mente preparar otro post paso a paso indicando como hacerlo y las herramientas para lograrlo. Continuando con la configuración de la ejecución, si sencillamente con botón derecho del ratón hacemos clic en Run ‘App’ nos arrojará el error.

Exception in thread “main” java.lang.NoClassDefFoundError: org/apache/spark/sql/SparkSession$
at com.josedeveloper.App$.main(App.scala:13)
at com.josedeveloper.App.main(App.scala)
Caused by: java.lang.ClassNotFoundException: org.apache.spark.sql.SparkSession$
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
… 2 more

Error ejecutando la clase App

El error se debe a que no encuentra las clases con las que fue compilado previamente y eso se debe a que las dependencias de spark las hemos añadido con el alcance “provided”.
¿Por qué provided? Debido a que en un entorno empresarial esas dependencias no debemos agregarlas ya que las provee la infraestructura Big Data de la empresa.

Entonces para solventar el error sencillamente debemos ir al menu “Run” y hacemos clic en “Edit Configurations” y allí marcamos la opción de incluir dependencias provided (Include dependencies with “Provided” scope).

Marcamos la opción que incluya las dependencias con alcance “Provided”

Hecho eso volvemos a ejecutar la clase App y veremos como si se logra ejecutar la aplicación. Sin más espero que les haya servido de ayuda y les comento que mi próximo paso será crear un archetype (arquetipo) y a su vez explicarles como hacerlo para que cada quien pueda construir uno acorde con las necesidades de su organización y así dotamos de más profesionalidad y agilidad nuestro trabajo y evitamos el copiar+pegar donde en ocasiones terminamos añadiendo mas dependencias y plugins innecesarios así como también arrastrando problemas y errores (de haberlos).

Aquí les dejo el video

Repo GitHub

Primeros pasos con maven Parte I

Desde su nacimiento Maven ha ido consolidando y a su vez aumentando su posición como herramienta de gestión y construcción de software en lenguaje Java, poco a poco quitandole terreno a otra famosa herramienta presente en el mercado desde hace mas tiempo que de seguro mucho de ustedes la habran oido mencionar Apache Ant.

A continuación les dejo unas graficas sacadas con el software de estadistica de google donde se puede observar como ha ido incrementandose el interes de Maven con respecto a Ant en distintas categorias

 

estadísticas de Ant vs Maven en la categoria de Programación estadísticas de Ant vs Maven en la categoria Herramientas de desarrollo
estadísticas de Ant vs Maven en la categoría Lenguaje de programación Java estadísticas del crecimiento de las búsquedas de Ant y Maven vs  la categoria Lenguaje de programación Java
estadísticas de las búsquedas de Ant vs Maven en la categoría Software

Además es cuestión de revisar ofertas de trabajo para ver como cada vez piden mas el conocer Maven como requisito indispensable o como poco un requisito deseado a poseer por parte del candidato. Dada esta introducción quiero compartir con ustedes lo poco que se y he aprendido de maven con la finalidad de que pueda serles de utilidad o al menos como incentivo a aprender mas de esta poderosa herramienta.

Instalación

Debemos ir al sitio web de Maven y descargar los binarios, como vamos a ir haciendo cosas sencillas les recomiendo que empecemos con la versión 3 para ir familiarizandonos con las novedades de esta nueva versión (según he leido goza de mejoras de productividad, errores, además de escribir el fichero POM en otros lenguajes no XML como groovy, ruby, scala entre otros).

NOTA: Antes de realizar los siguientes pasos de la instalación, asumimos que ya de antemano existe la variable JAVA_HOME apuntando a la ruta donde tenemos instalado nuestra versión de Java y que a su vez los binarios de Java ya han sido añadidos al PATH del sistema.

Usuarios Windows XP

  1. Una vez descargado el software, descomprimirlo en la carpeta de preferencia, por ejemplo para usuarios windows podria ser la ruta C:\Archivos de programa\apache-maven,
  2. Creamos las variables de entorno en panel de control->Sistema->Opciones avanzadas->variables de entorno. Alli crearemos 2 nuevas variables del sistema. La primera será M2_HOME su valor será la ruta (path) donde hallamos instalado maven p.e. C:\Archivos de programa\apache-maven\apache-maven-3.0.4. La segunda variable será M2 y su valor será %M2_HOME%\bin.
  3. Editamos la variable del sistema PATH, y agregamos al final del contenido del valor de la variable PATH, el valor de la variable M2, de la siguiente manera:valor_variable_path;%M2%.
  4. Probamos que los pasos anteriores se han efectuado correctamente, Por linea de comandos (inicio->ejecutar: cmd.exe) tecleamos mvn -version y deberá aparecer la información de maven, como por ejemplo la versión java, la versión maven, la ruta de instalación, etc.

Usuarios Linux/Mac Os X

  1. Una vez descargado maven, lo extraemos en nuestro lugar de preferencia, pero podriamos utilizar la ruta /usr/local/apache-maven.
  2. En el terminal por linea de comando, exportamos la variable M2_HOME con el valor de la ruta donde hemos instalado maven por ejemplo,  export M2_HOME = /usr/local/apache-maven/apache-maven-3.0.4. De igual manera hacemos con la variable M2, de la siguiente manera, export M2=$M2_HOME/bin.
  3. Agregamos al PATH la variable M2, de la siguiente manera, export PATH=$M2:$PATH.
  4. Probamos que los pasos anteriores se han efectuado correctamente, Por linea de comandos  tecleamos mvn -version y deberá aparecer la información de maven, como por ejemplo la versión java, la versión maven, la ruta de instalación, etc.

Configuración opcional

Si entramos en la ruta donde hemos instalado maven encontraremos el fichero settings.xml dentro de la carpeta conf, este fichero nos permite configurar aspectos adicionales, como pueden ser modificar la ruta por defecto donde se alojara nuestro repositorio o indicar una conexón proxy, entre otras cosas.

Si estamos conectados por medio de un servidor proxy sencillamente descomentamos el contenido de la etiqueta proxies y alli indicamos los valores con lo cual accedemos a conectarnos. por ejemplo

Por otro lado si desearamos modificar la ruta por defecto del repositorio, solo descomentariamos el contenido de la etiqueta local_repository y colocamos la ruta donde deseemos que este ubicado nuestro repositorio, por ejemplo en windows podría ser algo como esto:

 

Ahora que ya tenemos maven instalado, configurado y tenemos constancia de ello (habiendo efectuado las pruebas), vamos a crear nuestro primer proyecto Maven, lo haremos por linea de comandos y tecleamos lo siguiente:

mvn archetype:generate -DgroupId=com.josedeveloper.app -DartifactId=PruebaMaven -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Esta sentencia nos creara todo el esqueleto del Proyecto incluyendo un fichero de pruebas y un main (con un “Hola mundo!”), la primera vez puede que tarde un poco, ya que maven estara descargandose las ultimas versiones de los plug-ins a nuestro repositorio, incluso en el sitio web de Maven nos indican que puede que esta sentencia debamos ejecutarla en más de una oportunidad ya que pueden ocurrir time out antes de que se haya terminado la descarga (esperemos que no sea nuestro caso).

Una vez creado el proyecto veremos una carpeta de nombre PruebaMaven (o cualquier otro que hayamos utilizado) si entramos en esa carpeta nos encontraremos con el fichero pom.xml y este no es mas que el fichero que maneja la configuración de nuestro proyecto (haciendo una analogia vendria siendo algo asi como el build.xml de Ant).

Maven funciona en torno a fases, y una fase no es más que un paso dentro del ciclo de vida de construcción de un proyecto, es importante tener en cuenta que para llegar a una fase es necesario haber pasado previamente por las fases que le preceden. Las fases por defecto más comunes de un proyecto serían las siguientes:

  • validate: Valida que el proyecto esta correcto y dispone de la información necesaria.
  • compile: Compila el código fuente del proyecto.
  • test: Prueba el código fuente compilado haciendo uso de frameworks para pruebas unitarias (JUnit).
  • package: Empaqueta el código fuente compilado (por ejemplo creando un jar o war).
  • integration-test: Procesa y despliega el paquete dentro de un entorno de test de integración.
  • verify: Ejecuta los controles necesarios para  verificar si el paquete es válido y cumple con los criterios de calidad.
  • install: Instala el paquete dentro del repositorio local, para poder usarlo como dependencia en otro proyecto.
  • deploy: Copia el paquete final al repositorio remoto para compartir con otros desarrolladores y proyectos.

Analizando lo anterior  y volviendo a lo de las fases, nos damos cuenta que tiene mucha logica el enfoque de fases de Maven, ya que para poder probar un código, es necesario haberlo compilado de antemano, lo cual implica haber pasado por la fase compile, así como para poder instalar un proyecto como dependencia en el repositorio es necesario que el código haya sido compilado, se haya probado, luego empaquetarlo, lo que se traduce que al invocar la fase install previamente tuvo que haber pasado por las fases, compile, test, package… y asi sucesivamente.

Ahora procedamos a construir el proyecto, sencillamente ubicandonos dentro de la carpeta del proyecto, introducimos por linea de comandos, lo siguiente

mvn package

Si navegamos por la estructura de directorio veremos que en la carpeta target nos habra creado un fichero .jar, además que durante la ejecución de la ultima sentencia podemos ver como se van ejecutando las fases previas al empaquetado.

Ya empaquetado el proyecto procedemos a ejecutarlo y lo haremos también por linea de comandos introduciendo la siguiente sentencia

>java -cp .\target\PruebaMaven-1.0-SNAPSHOT.jar com.josedeveloper.app.App

Podremos ver nuestro Hola Mundo! con nuestro primer proyecto maven.

Por ultimo quizás se hayan dado cuenta que algunos warning se arrojaron por linea de comando al momento del empaquetado, eso podemos resolverlo muy facilmente agregando a nuestro fichero pom.xml la siguiente linea

 

quedando este ultimo así

Conclusión

Toparse de repente con maven en un proyecto, al principio puede ser un dolor de cabeza, genera muchas interrogantes, además que la curva de aprendizaje a mi modo de ver no es de la mas rapidas, lo cual puede que nos genere uno que otro enfado, impotencia, pero a medida que se va aprendiendo y poniendo a prueba las bondades de esta herramienta  ocurre un cambio como decir el pasar del odio al amor jajajaja, esto no lo tomen como una generalización sino que es una opinion personal, pero es lo que he percibido a medida que voy avanzado con Maven, entre los beneficios (gracias a la gran cantidad de plugins) pues yo brevemente destaco el poder tener un repositorio centralizado, identificando las dependencias por sus respectivas versiones, es decir, olvidemonos de la cantidad infinita de jars repetidos en cada proyecto, además de poder utilizarlo para temas de testing e integración continua, además de poder crear esqueletos de proyectos adaptados a nuestras necesidades, ya para mi lo anteriormente expuesto ya hace que valga la pena aprender a usar la herramienta, es más si les soy sincero yo aun estoy conociendo las ventajas de usar Maven y espero en medida de lo posible poderlo compartir con ustedes. De igual manera les invito a compartir sus experiencias con maven, que otras ventajas o desventajas observan ustedes de usarlo así como compartir material de interés.