Aprendiendo Spark: #2 Hola mundo
Tags: tutorial, apachespark, python, bigdata
Published: 2021-02-20 18:55:29

---
title: Aprendiendo Spark: #2 Hola mundo
published: true
description: Introducción y fundamentos básicos del framework de computación distribuida Apache Spark
tags: tutorial, apachespark, python, bigdata
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/16rztt4e7iv48tdphojy.png
---

¡Saludos, camaradas! 👋

En este artículo vamos a analizar el código del "Hola mundo" que expusimos en el artículo anterior. Antes de nada, vamos a recordarlo:

```python
from pyspark.sql import SparkSession

# Iniciamos Spark de manera local
spark = (SparkSession
         .builder
         .master("local[*]")
         .appName("Hola Mundo")
         .getOrCreate())

# Paralelizamos una lista del 0 al 9 (incluido)
# Computamos la suma de los números
# Obtenemos el resultado en una variable
result = (spark
          .sparkContext
          .parallelize(range(10))
          .reduce(lambda x, y: x + y))

# Imprimimos el resultado
print(f"La suma es {result}")
```

Al ejecutarlo a través del IDE o mediante una terminal escribiendo `python hola_mundo.py` veremos el siguiente output tras una serie de warnings:

```
La suma es 45

Process finished with exit code 0
```

Vale, muy bonito todo pero, ¿qué es cada cosa?

# Creando la sesión de Spark

Para continuar vamos a dar una vuelta por nuestro código anotando los tipos de nuestras variables.

> **Friendly reminder**: Anotar con tipos en Python es meramente informativo de cara a quien desarrolla el código, no tiene el efecto que pueda tener en lenguajes como Java.

Vamos a anotar con su tipo la variable `spark` y también vamos a poner un comentario en cada una de las llamadas encadenadas durante la creación de dicho objeto, para que veamos de qué tipo es cada una.

```python
spark: SparkSession = (SparkSession             # SparkSession
                       .builder                 # Builder
                       .master("local[*]")      # Builder
                       .appName("Hola Mundo")   # Builder
                       .getOrCreate())          # SparkSession

```

Todo empieza con la referencia a la clase `SparkSession`, ésta nos permite crear un objeto `Builder` al cual le iremos indicando qué configuración queremos. 

En primer lugar, indicaremos que el `master()` es local usando todos los cores que dispongamos. Esto es típico para hacer pruebas en local, cuando no disponemos de un clúster donde ejecutar código productivo (y de momento nos sirve perfectamente).

En segundo lugar especificamos el nombre de nuestra ejecución mediante `appName()`. Como no podía ser de otra manera, se llama "Hola mundo" (cuánta imaginación, ¿verdad? 🙄).

Tanto las llamadas a `master()` como a `appName()` devuelven un objeto Builder, que indica que está a medio construir, nos faltaría un paso más.

Por último le indicamos a Spark que nos devuelva (en caso de existir) o que nos cree (en caso contrario) una `SparkSession` con la que podamos hacer computación distribuida.

La `SparkSession` que nos devuelve la plasmamos en la variable `spark` para que podamos utilizarla más adelante. 

> ¡Llegados a este punto ya podemos empezar a hacer computación distribuida!

# Pinto y coloreo mis primeras operaciones distribuidas 🤓

Ahora vamos a hacer lo mismo con el segundo bloque de código, anotando el tipo de la variable `result` y comentando cada paso.

```python
result: int = (spark                          # SparkSession
               .sparkContext                  # SparkContext
               .parallelize(range(10))        # RDD[int]
               .reduce(lambda x, y: x + y))   # int
```

Primero partimos de la variable `spark` creada previamente. Y a partir de ella obtenemos un objeto `SparkContext`. Podemos entender este objeto como un _helper_ de Spark para realizar ciertas maniobras. En este caso nos facilita la creación de un [RDD](https://spark.apache.org/docs/latest/api/python/pyspark.html#pyspark.RDD) a través de su método `parallelize`, que toma una lista como argumento.

Con `parallelize()` tomamos una lista clásica (un array de toda la vida, si queréis verlo así) y crea un RDD a partir de ella, del mismo tipo de la lista. Nosotros le hemos pasado la lista `[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]` resultante de invocar `range(10)`, que es de tipo `int`. Por lo tanto el `RDD` será también de tipo `int`.

## Explícame un poco los RDDs, porfa 🥺

Los `RDD`s son las unidades básicas de Spark a partir de las cuales podemos hacer computación distribuida. En próximos artículos entraremos en más profundidad, de momento nos sirve pensar en ellos como **listas cuyo contenido está troceado y repartido por diferentes servidores de Spark**.

De esta manera, evitamos cargar a un único servidor con todo el trabajo, ya que todos los nodos que tengamos trabajarán a la par. ¿Y cuál es ese trabajo tan tedioso que va a requerir computación distribuida? 🤔

¡Nada más y nada menos que la **acción** `reduce()`! 🤩

> Importante: Este `reduce()` no es el del módulo `functools` pero se comporta parecido, solo que de manera distribuida.

## Acción `reduce()`

Vale, ¿entonces qué hace exactamente el `reduce()` de un `RDD`?

Esta función coge una lista distribuida (`RDD`) y va combinando sus valores mediante la función que le indiquemos. En este caso ha sido una simple función anónima que suma 2 números que le pase `reduce()`. 

> Si no estáis familiarizados con funciones combinatorias de programación funcional, os dejo [una breve explicación](https://www.geeksforgeeks.org/reduce-in-python/) del `reduce()` del módulo functools. Recordad que no es lo mismo, pero nos sirve para hacernos una idea general de cuál es su mecánica.

Así pues, lo que hará es sumar todos los valores de la lista y devolverá un resultado, un simple `int` de toda la vida. En este proceso intervendrían todos nuestros servidores de Spark, comunicándose entre ellos para ir sumando los diferentes valores, hasta tener completada la suma de todos ellos y devolver el resultado.

Una vez tenemos ese número en nuestro poder, lo imprimimos por pantalla para conocer el resultado de tamaña operación. ¡Buen trabajo! 😎

Espero que os haya sido útil este artículo. En el próximo hablaremos en más profundidad de las operaciones de Spark, que se dividen en **transformaciones** y **acciones**. 

Es muy importante entender bien el rol y efectos que las diferencian, ¡así que os espero en el próximo artículo! 🤗

¡Nos vemos, equipo! 🙌