

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Tres tipos de trabajos de AWS Glue ETL para convertir datos a Apache Parquet
<a name="three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet"></a>

*Adnan Alvee, Nith Govindasivan y Karthikeyan Ramachandran, Amazon Web Services*

## Resumen
<a name="three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet-summary"></a>

En la nube de Amazon Web Services (AWS), AWS Glue es un servicio de extracción, transformación y carga (ETL) totalmente administrado. Con AWS Glue puede categorizar datos, limpiarlos, enriquecerlos y trasladarlos de manera fiable entre distintos almacenes y flujos de datos de manera rentable.

Este patrón proporciona diferentes tipos de trabajos en AWS Glue y utiliza tres scripts diferentes para demostrar la creación de trabajos de ETL.

Puede usar AWS Glue para escribir trabajos de ETL en un entorno de intérprete de comandos de Python. También puede crear trabajos ETL por lotes o en streaming mediante Python (PySpark) o Scala en un entorno Apache Spark gestionado. Para empezar a crear trabajos de ETL, este patrón se centra en los trabajos de ETL por lotes utilizando Python shell y Scala. PySpark Los trabajos de intérprete de comandos de Python están pensados para cargas de trabajo que requieren menos potencia de cálculo. El entorno gestionado de Apache Spark está diseñado para cargas de trabajo que requieren una gran potencia de cálculo.

Apache Parquet está diseñado para admitir esquemas de compresión y codificación eficientes. Puede acelerar sus cargas de trabajo de análisis porque almacena los datos en forma de columnas. La conversión de datos a Parquet puede ahorrarle espacio de almacenamiento, costos y tiempo a largo plazo. Para obtener más información sobre Parquet, consulte la entrada del blog [Apache Parquet: cómo ser un héroe con el formato de datos en columnas de código abierto](https://blog.openbridge.com/how-to-be-a-hero-with-powerful-parquet-google-and-amazon-f2ae0f35ee04).

## Requisitos previos y limitaciones
<a name="three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet-prereqs"></a>

**Requisitos previos **
+ Rol de AWS Identity and Access Management (IAM) (si no tiene un rol, consulte la sección de [Información adicional](#three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet-additional)).

## Arquitectura
<a name="three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet-architecture"></a>

**Pila de tecnología de destino**
+ AWS Glue
+ Amazon Simple Storage Service (Amazon S3)
+ Apache Parquet

**Automatizar y escalar**
+ [Los flujos de trabajo de AWS Glue](https://docs.aws.amazon.com/glue/latest/dg/workflows_overview.html) admiten la automatización total de una canalización de ETL.
+ Puede cambiar el número de unidades de procesamiento de datos (DPUs), o los tipos de trabajadores, para escalar horizontal y verticalmente.

## Tools (Herramientas)
<a name="three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet-tools"></a>

**Servicios de AWS**
+ [Amazon Simple Storage Service (Amazon S3)](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html) es un servicio de almacenamiento de objetos basado en la nube que le ayuda a almacenar, proteger y recuperar cualquier cantidad de datos.
+ [AWS Glue](https://docs.aws.amazon.com/glue/latest/dg/what-is-glue.html) es un servicio de ETL totalmente gestionado que le ayuda a clasificar, limpiar, enriquecer y mover datos de forma fiable entre almacenes de datos y flujos de datos.

**Otras herramientas**
+ [Apache Parquet](https://parquet.apache.org/) es un formato de archivo de datos de código abierto orientado por columnas diseñado para el almacenamiento y la recuperación.

**Configuración**

Utilice los siguientes ajustes para configurar la potencia de procesamiento de AWS Glue ETL. Para reducir los costos, utilice la configuración mínima cuando ejecute la carga de trabajo que se proporciona en este patrón. 
+ **Intérprete de comandos de Python**: puede usar 1 DPU para utilizar 16 GB de memoria o 0,0625 DPU para utilizar 1 GB de memoria. Este patrón usa 0,0625 DPU, que es el valor predeterminado en la consola de AWS Glue.
+ **Python o Scala para Spark**: si elige los tipos de trabajo relacionados con Spark en la consola, AWS Glue utiliza de forma predeterminada 10 trabajadores y el tipo de trabajador G.1X. Este patrón utiliza dos trabajadores, que es el número mínimo permitido, y el tipo de trabajador estándar es suficiente y rentable.

En la siguiente tabla se muestran los distintos tipos de trabajadores de AWS Glue para el entorno Apache Spark. Como un trabajo de intérprete de comandos de Python no utiliza el entorno Apache Spark para ejecutar Python, no se incluye en la tabla.


| 
| 
|  | Standard | G.1 X | G.2X | 
| --- |--- |--- |--- |
| vCPU | 4 | 4 | 8 | 
| Memoria | 16 GB | 16 GB | 32 GB | 
| Espacio en disco | 50 GB | 64 GB | 128 GB | 
| Ejecutor por trabajo | 2. | 1  | 1 | 

**Código**

Para ver el código que se utiliza en este patrón, incluida la configuración del rol de IAM y los parámetros de IAM, consulte la sección de [Información adicional](#three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet-additional).

## Epics
<a name="three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet-epics"></a>

### Carga de datos
<a name="upload-the-data"></a>


| Tarea | Descripción | Habilidades requeridas | 
| --- | --- | --- | 
| Cargue los datos en un bucket de S3 nuevo o en un bucket de S3 ya existente. | Cree utilice un bucket de S3 existente en su cuenta. Cargue el archivo sample\_data.csv de la sección de [Adjuntos](#attachments-8c926709-8fa4-417f-9aaf-bcc8113d018f) y anote el bucket de S3 y la ubicación del prefijo. | AWS general | 

### Cree y ejecute el trabajo de AWS Glue
<a name="create-and-run-the-aws-glue-job"></a>


| Tarea | Descripción | Habilidades requeridas | 
| --- | --- | --- | 
| Cree el trabajo de AWS Glue | En la sección ETL de la consola de AWS Glue, añada un trabajo de AWS Glue. Seleccione el tipo de trabajo adecuado, la versión de AWS Glue y el DPU/Worker tipo y número de trabajadores correspondientes. Para más información, consulte la sección *Configuración*. | Desarrollador, nube o datos | 
| Cambie las ubicaciones de entrada y salida. | Copie el código correspondiente a su trabajo de AWS Glue y cambie la ubicación de entrada y salida que indicó en la descripción de la épica **Cargar los datos**. | Desarrollador, nube o datos | 
| Configure los parámetros. | Puede utilizar los fragmentos que se proporcionan en la sección de [Additional information](#three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet-additional) (Información adicional) para establecer los parámetros de su trabajo de ETL. AWS Glue utiliza cuatro nombres de argumentos internamente:[See the AWS documentation website for more details](http://docs.aws.amazon.com/es_es/prescriptive-guidance/latest/patterns/three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet.html)<br />El parámetro `--JOB_NAME` debe introducirse de forma explícita en la consola de AWS Glue. Elija **Trabajos**, **Edit Job** (Editar trabajo), **Security configuration, script libraries, and job parameters (optional)** (Configuración de seguridad, bibliotecas de scripts y parámetros de trabajo (opcional)). Introduzca `--JOB_NAME` como clave y proporcione un valor. También puede utilizar la Interfaz de la línea de comandos de AWS (AWS CLI) o la API de AWS Glue para configurar este parámetro. Spark usa el parámetro `--JOB_NAME` y no es necesario en un trabajo de entorno de intérprete de comandos de Python.<br />Debe añadir `--` antes del nombre de cada parámetro; de lo contrario, el código no funcionará. Por ejemplo, en el caso de los fragmentos de código, los parámetros de ubicación deben invocarse mediante `--input_loc` y `--output_loc`. | Desarrollador, nube o datos | 
| Ejecute el trabajo de ETL. | Ejecute su trabajo y compruebe el resultado. Observe cuánto espacio se ha reducido con respecto al archivo original. | Desarrollador, nube o datos | 

## Recursos relacionados
<a name="three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet-resources"></a>

**Referencias**
+ [Apache Spark](https://spark.apache.org/)
+ [AWS Glue: cómo funciona](https://docs.aws.amazon.com/glue/latest/dg/how-it-works.html)
+ [Precios de AWS Glue](https://aws.amazon.com/glue/pricing/)

**Tutoriales y videos**
+ [¿Qué es AWS Glue?](https://www.youtube.com/watch?v=qgWMfNSN9f4)

## Información adicional
<a name="three-aws-glue-etl-job-types-for-converting-data-to-apache-parquet-additional"></a>

**Rol de IAM**

Al crear los trabajos de AWS Glue, puede usar un rol de IAM existente que tenga los permisos que se muestran en el siguiente fragmento de código o un rol nuevo.

Para crear un nuevo rol, utilice el siguiente código YAML.

```
# (c) 2022 Amazon Web Services, Inc. or its affiliates. All Rights Reserved. This AWS Content is provided subject to the terms of the AWS Customer
# Agreement available at https://aws.amazon.com/agreement/ or other written agreement between Customer and Amazon Web Services, Inc.

AWSTemplateFormatVersion: "2010-09-09"

Description: This template will setup IAM role for AWS Glue service.

Resources:
  rGlueRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "glue.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole
      Policies:
        - PolicyName: !Sub "${AWS::StackName}-s3-limited-read-write-inline-policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "s3:PutObject"
                  - "s3:GetObject"
                Resource: "arn:aws:s3:::*/*"
      Tags:
        - Key  : "Name"
          Value : !Sub "${AWS::StackName}"

Outputs:
  oGlueRoleName:
    Description: AWS Glue IAM role
    Value:
      Ref: rGlueRole
    Export:
      Name: !Join [ ":", [ !Ref "AWS::StackName", rGlueRole ] ]
```

**AWS Glue (intérprete de comandos de Python)**

El código Python usa los Pandas y PyArrow las bibliotecas para convertir los datos a Parquet. La biblioteca Pandas ya está disponible. La PyArrow biblioteca se descarga al ejecutar el patrón, ya que se ejecuta una sola vez. Puede usar archivos de rueda PyArrow para convertirlos en una biblioteca y proporcionar el archivo como un paquete de biblioteca. Para obtener más información, consulte [Proporcionar su propia biblioteca de Python](https://docs.aws.amazon.com/glue/latest/dg/add-job-python.html)

*Parámetros del intérprete de comandos de Python de AWS Glue*

```
from awsglue.utils import getResolvedOptions

args = getResolvedOptions(sys.argv, ["input_loc", "output_loc"])
```

*Código del intérprete de comandos para Python de AWS Glue*

```
from io import BytesIO
import pandas as pd
import boto3
import os
import io
import site
from importlib import reload
from setuptools.command import easy_install
install_path = os.environ['GLUE_INSTALLATION']
easy_install.main( ["--install-dir", install_path, "pyarrow"] )
reload(site)
import pyarrow


input_loc = "s3://bucket-name/prefix/sample_data.csv"
output_loc = "s3://bucket-name/prefix/"


input_bucket = input_loc.split('/', 1)[0]
object_key = input_loc.split('/', 1)[1]


output_loc_bucket = output_loc.split('/', 1)[0]
output_loc_prefix = output_loc.split('/', 1)[1] 


s3 = boto3.client('s3')
obj = s3.get_object(Bucket=input_bucket, Key=object_key)
df = pd.read_csv(io.BytesIO(obj['Body'].read()))


parquet_buffer = BytesIO()
s3_resource = boto3.resource('s3')
df.to_parquet(parquet_buffer, index=False) 
s3_resource.Object(output_loc_bucket, output_loc_prefix +  'data' + '.parquet').put(Body=parquet_buffer.getvalue())
```

**Trabajo de AWS Glue Spark con Python**

Para usar un tipo de trabajo de AWS Glue Spark con Python, elija **Spark** como tipo de trabajo. Elija **Spark 3.1, Python 3 con un tiempo de inicio de trabajo mejorado (Glue versión 3.0)** como versión AWS Glue.

*Parámetros de Python de AWS Glue*

```
from awsglue.utils import getResolvedOptions

args = getResolvedOptions(sys.argv, ["JOB_NAME", "input_loc", "output_loc"])
```

*Trabajo de AWS Glue Spark con el código de Python*

```
import sys
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.transforms import *
from awsglue.dynamicframe import DynamicFrame
from awsglue.utils import getResolvedOptions
from awsglue.job import Job


sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)

input_loc = "s3://bucket-name/prefix/sample_data.csv"
output_loc = "s3://bucket-name/prefix/"

inputDyf = glueContext.create_dynamic_frame_from_options(\
    connection_type = "s3", \
    connection_options = { 
        "paths": [input_loc]}, \
    format = "csv",
    format_options={
        "withHeader": True,
        "separator": ","
    })


outputDF = glueContext.write_dynamic_frame.from_options(\
    frame = inputDyf, \
    connection_type = "s3", \
    connection_options = {"path": output_loc \
        }, format = "parquet")
```

En el caso de un gran número de archivos comprimidos de gran tamaño (por ejemplo, 1000 archivos de aproximadamente 3 MB cada uno), utilice el parámetro `compressionType` junto con el parámetro `recurse` para leer todos los archivos disponibles en el prefijo, tal y como se muestra en el código siguiente.

```
input_loc = "bucket-name/prefix/"
output_loc = "bucket-name/prefix/"

inputDyf = glueContext.create_dynamic_frame_from_options(
                    connection_type = "s3", 
                    connection_options = {"paths": [input_loc], 
                                            "compressionType":"gzip","recurse" :"True",
                                            },
                    format = "csv",
                    format_options={"withHeader": True,"separator": ","}
                    )
```

Para un gran número de archivos pequeños comprimidos (por ejemplo, 1000 archivos de aproximadamente 133 KB cada uno), utilice el parámetro`groupFiles` junto con los parámetros `compressionType` y `recurse`. El parámetro `groupFiles` agrupa los archivos pequeños en varios archivos grandes y el parámetro `groupSize` controla la agrupación según el tamaño especificado en bytes (por ejemplo, 1 MB). El siguiente fragmento de código proporciona un ejemplo del uso de estos parámetros en el código.

```
input_loc = "bucket-name/prefix/"
output_loc = "bucket-name/prefix/"

inputDyf = glueContext.create_dynamic_frame_from_options(
                    connection_type = "s3", 
                    connection_options = {"paths": [input_loc], 
                                            "compressionType":"gzip","recurse" :"True",
                                             "groupFiles" :"inPartition",  "groupSize" :"1048576",
                                            },
                    format = "csv",
                    format_options={"withHeader": True,"separator": ","}
                    )
```

Sin ningún cambio en los nodos de trabajo, esta configuración permite que el trabajo de AWS Glue lea varios archivos (grandes o pequeños, con o sin compresión) y los escriba en el destino en formato Parquet.

**Trabajo de AWS Glue Spark con Scala**

Para usar un tipo de trabajo de AWS Glue Spark con Scala, elija **Spark** como tipo de trabajo y un **Language** (Idioma) como **Scala**. Elija **Spark 3.1, Scala 2 con un tiempo de inicio de trabajo mejorado (Glue versión 3.0)** como versión de AWS Glue. Para ahorrar espacio de almacenamiento, en el siguiente ejemplo de AWS Glue with Scala también se utiliza la característica `applyMapping` para convertir tipos de datos.

*Parámetros de AWS Glue Scala*

```
import com.amazonaws.services.glue.util.GlueArgParser val args = GlueArgParser.getResolvedOptions(sysArgs, Seq("JOB_NAME", "inputLoc", "outputLoc").toArray)
```

*Trabajo de AWS Glue Spark con código Scala*

```
import com.amazonaws.services.glue.GlueContext
import com.amazonaws.services.glue.MappingSpec
import com.amazonaws.services.glue.DynamicFrame
import com.amazonaws.services.glue.errors.CallSite
import com.amazonaws.services.glue.util.GlueArgParser
import com.amazonaws.services.glue.util.Job
import com.amazonaws.services.glue.util.JsonOptions
import org.apache.spark.SparkContext
import scala.collection.JavaConverters._


object GlueScalaApp {
  def main(sysArgs: Array[String]) {
    
    @transient val spark: SparkContext = SparkContext.getOrCreate()
    val glueContext: GlueContext = new GlueContext(spark)

    val inputLoc = "s3://bucket-name/prefix/sample_data.csv"
    val outputLoc = "s3://bucket-name/prefix/"

    val readCSV = glueContext.getSource("csv", JsonOptions(Map("paths" -> Set(inputLoc)))).getDynamicFrame()

    val applyMapping = readCSV.applyMapping(mappings = Seq(("_c0", "string", "date", "string"), ("_c1", "string", "sales", "long"),
    ("_c2", "string", "profit", "double")), caseSensitive = false)

    val formatPartition = applyMapping.toDF().coalesce(1)

    val dynamicFrame = DynamicFrame(formatPartition, glueContext)

    val dataSink = glueContext.getSinkWithFormat(
        connectionType = "s3", 
        options = JsonOptions(Map("path" -> outputLoc )),
        transformationContext = "dataSink", format = "parquet").writeDynamicFrame(dynamicFrame)
  }
}
```

## Conexiones
<a name="attachments-8c926709-8fa4-417f-9aaf-bcc8113d018f"></a>

Para acceder al contenido adicional asociado a este documento, descomprima el archivo: [attachment.zip](samples/p-attach/8c926709-8fa4-417f-9aaf-bcc8113d018f/attachments/attachment.zip)