# Tema 4 · 3 · Ejercicio 2: NYC Taxi (Parquet, particiones, vista y tabla curated) Presentación del Tema 4: «Ejercicio 2 – NYC Taxi». Duración: 45 a 60 minutos, de los que la carga de datos con el script son 1 o 2. Coste: céntimos (unos 300 MB descargados a CloudShell y subidos a S3; Athena con decenas de MB). > **¿Dudas con un script?** Todos los scripts de esta carpeta traen su propia ayuda: `./gestionar-nyc-taxi.sh --ayuda` (también vale `--help` o `-h`) explica los pasos y las opciones. Este `README.md` es el paso a paso de la actividad: tenlo a mano y consúltalo antes de preguntar. > **Etiquetas de lo que creas.** Este ejercicio no crea recursos propios: trabaja dentro de los de `04.01-creardatalake`, que ya llevan las etiquetas `curso` = `G214`, `universidad` = `CUNEF` y `actividad` = `04.01-creardatalake`. Más detalle (cómo etiquetar con la CLI, cómo buscar y qué hacer en una emergencia): [README principal](../../README.md), sección «Etiquetas». ## Qué vas a hacer Vas a cargar cinco meses de viajes de los taxis amarillos de Nueva York (ficheros Parquet de unos 60 MB cada uno) en tu Data Lake con un script, crear una tabla particionada por año y mes, una vista con columnas calculadas y una tabla limpia (curated), y después resolver en Athena los ejercicios de la presentación. **Qué se crea en AWS** (dentro del stack de [04.01](../04.01-creardatalake/README.md)): los ficheros `raw/nyc_taxi/year=YYYY/month=MM/yellow_tripdata_YYYY-MM.parquet` en tu bucket y, en la base `demo_datalake_db`, la tabla externa `nyc_taxi_yellow_raw`, la vista `v_nyc_taxi_yellow` y la tabla `nyc_taxi_yellow_curated` (Parquet, con ficheros en `athena-results/tables/`). ## Qué contiene esta carpeta | Fichero | Para qué sirve | Paso en que se usa | |---|---|---| | `gestionar-nyc-taxi.sh` | Gestor del ejercicio: `crear` (descarga los datos de NYC Taxi, los sube a S3 y crea tablas y vista), `estado` (qué hay cargado) y `eliminar` (borra lo de este ejercicio sin tocar el stack). Sin órdenes abre un menú | Pasos 2 y 3 y limpieza | | `2-athena-nyc-taxi.sql` | El SQL que ejecuta `gestionar-nyc-taxi.sh crear` (tabla, vista y tabla curated). Léelo: es la base de la presentación | Paso 3 | | `README.md` | Esta guía | - | ## Antes de empezar - Necesitas el Data Lake de [04.01 Crear el Data Lake](../04.01-creardatalake/README.md): el stack `g214-datalake-demo` en `CREATE_COMPLETE`, región `eu-north-1`. El script consulta el bucket directamente al stack con la AWS CLI; no lee ningún fichero de la otra carpeta. Si el stack no existe o no está en `CREATE_COMPLETE` se detiene con un mensaje que dice qué hacer. Antes de empezar comprueba también que `aws` es la versión 2, que tus credenciales son válidas y que tienes `curl` (o `wget`) para descargar. - **No necesitas haber hecho [04.02 Titanic](../04.02-titanic/README.md)**, pero en 04.02 se explica «Cómo leer Data scanned en Athena», que aquí se usa de nuevo (resumen en el paso 7). - Workgroup `demo-athena-workgroup` y base `demo_datalake_db` seleccionados en Athena (arriba a la derecha y panel izquierdo). No marques «Reuse query results». ## Cómo llevar los ficheros a CloudShell 1. En tu PC, comprime **esta carpeta** (`04.03-nyctaxi`, entera) en un zip y no la descomprimas. 2. En CloudShell (región `eu-north-1`): Actions > Upload file > `04.03-nyctaxi.zip`. 3. Descomprime, entra y da permisos: ```bash unzip -o 04.03-nyctaxi.zip && cd 04.03-nyctaxi && chmod -R u+rwX . && chmod +x *.sh ``` > Si ya subiste `g214-materiales.zip` (README principal), no necesitas este zip: entra con `cd ~/g214-materiales/tema4/04.03-nyctaxi` y, si algún fichero da `Permission denied`, ejecuta allí `chmod -R u+rwX . && chmod +x *.sh`. Ejecuta el script desde dentro de la carpeta: busca `2-athena-nyc-taxi.sql` en la carpeta actual y, si no está, junto al propio script. Si al ejecutarlo ves `bad interpreter` o errores con `\r`, el zip ha dejado finales de línea de Windows: `sed -i 's/\r$//' *.sh` y repite. ## Paso a paso ### Paso 1 · Averigua tu bucket ```bash BUCKET=$(aws cloudformation describe-stacks --stack-name g214-datalake-demo --region eu-north-1 \ --query "Stacks[0].Outputs[?OutputKey=='S3Bucket'].OutputValue" --output text) echo "$BUCKET" ``` Qué verás: `g214-datalake-demo-datalakebucket-`. (Repite el comando si CloudShell se cierra y vuelves más tarde.) ### Paso 2 · Elegir los meses `gestionar-nyc-taxi.sh` ya trae por defecto cinco meses de 2025 (`MONTHS=("2025-09" "2025-08" "2025-07" "2025-06" "2025-05")`, una línea cerca del principio del script, la que empieza por `MONTHS=(`): son los que usan las consultas de la presentación (`year = 2025`). **No tienes que editar nada.** Solo si quieres otros meses (la ciudad de Nueva York publica con unos dos meses de retraso: hay datos de 2024, 2025 y 2026 hasta el mes publicado), lo más fácil es pasárselos al ejecutarlo, sin editar el script: ```bash ./gestionar-nyc-taxi.sh crear --meses "2025-09 2025-08" ``` (formato `YYYY-MM`, separados por espacios; si algún mes no tiene ese formato, el script se detiene antes de descargar nada). Si prefieres cambiar el valor por defecto, edita esa línea con el editor `nano`: ```bash nano gestionar-nyc-taxi.sh ``` Busca la línea `MONTHS=(...)`, cámbiala (por ejemplo, para ir más rápido con solo dos meses, `MONTHS=("2025-09" "2025-08")`), guarda con Ctrl+O y Enter, y sal con Ctrl+X. O, sin editor, con una sola orden: ```bash sed -i 's/^MONTHS=.*/MONTHS=("2025-09" "2025-08")/' gestionar-nyc-taxi.sh grep -n '^MONTHS=' gestionar-nyc-taxi.sh ``` Qué verás: el `grep` muestra la línea `MONTHS=` con su número y tus meses. Ojo: si cambias a meses de otro año, las consultas con `year = 2025` devolverán 0 filas, y los valores de «Qué debes ver» del paso 6 solo valen con los cinco meses por defecto. ### Paso 3 · Cargar los datos ```bash ./gestionar-nyc-taxi.sh crear ``` (Sin `crear`, `./gestionar-nyc-taxi.sh` abre un menú numerado: `1) Crear`, `2) Ver estado`, `3) Eliminar lo de este ejercicio`, `0) Salir`. Las órdenes directas son `crear`, `estado`, `eliminar` y `ayuda`; también valen `--create`, `--status` y `--delete`.) No pide datos por teclado. Qué hace: por cada mes, descarga `yellow_tripdata_YYYY-MM.parquet` (unos 60 MB cada uno) de la web oficial de la ciudad de Nueva York a un directorio temporal, comprueba que es un Parquet válido (si la descarga falla, reintenta hasta 3 veces) y lo sube a `s3:///raw/nyc_taxi/year=YYYY/month=MM/`, borrando el fichero local nada más subirlo; después ejecuta `2-athena-nyc-taxi.sql`: crea la tabla externa `nyc_taxi_yellow_raw` (particionada por `year` y `month`), registra las particiones con `MSCK REPAIR TABLE`, crea la vista `v_nyc_taxi_yellow` (con duración, velocidad y porcentaje de propina), crea la tabla limpia `nyc_taxi_yellow_curated` y lanza 4 consultas de ejemplo (viajes por mes, percentiles de distancia, velocidad y propina, viajes más caros). Si algo falla (stack inexistente, un mes que aún no está publicado, una sentencia de Athena...) imprime qué ha pasado y qué hacer, sin trazas. Qué verás: por cada mes, una línea con la URL de descarga y otra con el destino de S3 y la línea `upload: ...`; después `Preparando SQL...` y 10 pares `Athena: ...` / `OK ()`; al final `Listo. NYC Taxi subido y tablas/vistas creadas en Athena.` **Tarda 1 o 2 minutos** (57 segundos con 2 meses, 1 min 17 s con 5, medido con la versión anterior del script). Igual que en el Titanic, no imprime los resultados de las consultas de ejemplo. Si repites el script: es seguro. Vuelve a descargar y subir los meses (nueva versión de cada fichero), y recrea la tabla, la vista y la curated. Si lo repites con **otros meses**, los de ejecuciones anteriores siguen en S3 y en las tablas (las particiones se acumulan). Los `.parquet` no quedan en tu disco: no hay nada que borrar en CloudShell. **Ver qué hay cargado:** `./gestionar-nyc-taxi.sh estado` muestra el estado del stack, los ficheros de `raw/nyc_taxi/` con su tamaño, si existen el workgroup y la base, cuáles de las tres tablas existen y cuántas particiones tiene `nyc_taxi_yellow_raw`. No cambia nada. ### Paso 4 · Verificar S3 y particiones ```bash aws s3 ls "s3://$BUCKET/raw/nyc_taxi/" --recursive --human-readable --region eu-north-1 ``` Qué verás: un fichero por mes, dentro de carpetas `year=2025/month=09/`, de decenas de MB cada uno. En Athena (base `demo_datalake_db`): ```sql SHOW PARTITIONS demo_datalake_db.nyc_taxi_yellow_raw; SELECT * FROM demo_datalake_db.nyc_taxi_yellow_raw LIMIT 10; ``` Qué verás: una partición por mes cargado (`year=2025/month=09`, etc.) y 10 viajes con sus columnas y `year`/`month` al final (algunas celdas salen vacías: `passenger_count`, `ratecodeid` y `airport_fee` son NULL en los viajes con `payment_type` 0). Si añades meses después, ejecuta `MSCK REPAIR TABLE demo_datalake_db.nyc_taxi_yellow_raw;` para registrarlos; si una tabla que sí tiene datos devuelve 0 filas, casi siempre es que faltan particiones por registrar. **Cuidado con `SELECT *`.** Aunque lleve `LIMIT 10`, Athena lee en paralelo antes de cortar: con los 5 meses por defecto, el Data scanned de `LIMIT 10` **no es estable**: lo medimos entre 2,6 y 9,7 MB con `SELECT *` y entre 17,7 y 35,6 MB con `WHERE passenger_count > 0`, según la ejecución (de unos 3 a unos 35 MB en total), y por eso no sirve para medir. **Sin `LIMIT` sí sale siempre lo mismo: unos 350 MB** (350.090.799 B); con más meses cargados todo crece. Y **sin `LIMIT` Athena guarda todas las filas como un CSV de varios GB** en `s3:///athena-results/.csv` (3,0 GiB con 20,6 millones de filas, en unos 2 minutos), y la consola solo pinta las primeras. Hazlo una vez para ver el efecto y bórralo después: busca el fichero con `aws s3 ls "s3://$BUCKET/athena-results/" --human-readable` y bórralo con `aws s3 rm "s3://$BUCKET/athena-results/.csv"` (el bucket está versionado: queda una versión antigua hasta que borres el stack). ### Paso 5 · Las tres tablas - `nyc_taxi_yellow_raw`: los datos tal como llegaron (zona raw). No se modifica. - `v_nyc_taxi_yellow`: una vista; no ocupa espacio, calcula `duration_min`, `mph` y `tip_rate` al vuelo y renombra las fechas a `pickup_ts` y `dropoff_ts`. - `nyc_taxi_yellow_curated`: tabla en Parquet creada desde la vista con filtros (`trip_distance > 0`, `fare_amount >= 0`; descarta un 9 % de los viajes: 18,8 millones de 20,6 con los 5 meses por defecto). **No filtra los importes absurdos**: el viaje más caro de algunos meses supera los 300.000 USD (un error de registro; ejercicio 7). Los ficheros de esta tabla también están bajo `athena-results/tables/` (mismo comportamiento que en el Titanic). Ahora haz los ejercicios de la presentación en Athena. Intenta resolverlos tú antes de mirar la tabla del paso 6. ### Paso 6 · Qué debes ver en los ejercicios 2 a 7 y el extra Para comprobar tus resultados con los cinco meses de 2025 por defecto (2025-05 a 2025-09; todas las cifras de esta tabla son de esos cinco meses, y con otros meses cambian): | Ejercicio | Qué debes ver | |---|---| | 2 · viajes por mes (70) | 2025-05 4.591.845; 2025-06 4.322.960; 2025-07 3.898.963; 2025-08 3.574.091; 2025-09 4.251.015. Data scanned 0 B (solo metadatos) | | 3 · duración media (71) | Decimales largos (`17.911712024252516`); con `ROUND(AVG(duration_min), 2)`: 17,91 / 17,41 / 17,10 / 17,28 / 18,59. La raw tiene duraciones negativas (hasta -681 min) y de hasta 11.295 min | | 4 · propinas por método de pago (72) | `payment_type`: 0 = Flex Fare, 1 = tarjeta de crédito, 2 = efectivo, 3 = sin cargo, 4 = disputa, 5 = desconocido, 6 = viaje anulado. Con `ROUND(AVG(tip_rate) * 100, 2)`: tarjeta (1) 14,24 %; Flex Fare (0) 0,80 %; efectivo (2) 0,0 %: la propina en efectivo no se registra. `tip_rate` es una fracción (0,1424), no un porcentaje | | 5 · tasa de aeropuerto mayor de 5 USD (73) | Solo hay filas desde 2025-05, cuando la tasa subió a 6,75 USD: 1.882 / 2.087 / 1.427 / 1.339 / 1.490 viajes (mayo a septiembre). Con meses de 2024 no sale nada | | 6 · total facturado (74) | Notación científica (`1.2148917115003005E8`); `ROUND` no la quita, `CAST(SUM(total_amount) AS DECIMAL(15,2))` sí: 121.489.171,15 / 116.050.555,08 / 102.892.243,72 / 93.311.611,67 / 116.020.613,40 | | 7 · viaje más caro (75) | Importes absurdos: 1.614,29 (mayo); 325.528,45 (junio); 5.297,87; 2.123,44; 323.820,17 (septiembre). La mediana es de unos 22 USD: son errores de registro que la curated no filtra | | Extra · día de la semana (76) | 7 filas (1 = lunes ... 7 = domingo). Con `ROUND(AVG(tip_rate) * 100, 2)`, el martes tiene el mayor porcentaje de propina (9,81 %) y el domingo el menor (8,13 %); el viernes y el sábado también bajan. Es un patrón del dato, no una causa probada | ### Paso 7 · Mide lo que escaneas (recordatorio) Tras cada consulta, anota Run time y Data scanned (en los resultados de Athena o en Recent queries). Data scanned es lo que Athena leyó de S3 y lo que se factura (5 USD por TB, mínimo 10 MB por consulta). Compara solo cambiando una cosa cada vez, no marques «Reuse query results» (saldría 0 bytes), no uses `COUNT(*)` sobre Parquet (0 B, solo metadatos) y no mides con `LIMIT` (no es estable): usa `SUM` o `AVG`. La explicación completa está en [04.02, «Cómo leer Data scanned en Athena»](../04.02-titanic/README.md#cómo-leer-data-scanned-en-athena). ### Paso 8 · (Opcional) Panel Streamlit Si creaste el stack con la instancia EC2 (el valor por defecto), ya puedes ver estos datos en un panel web: [04.07 Panel Streamlit y seguridad](../04.07-PanelStreamlitSeguridad.md). ## Errores frecuentes | Qué ves | Causa | Solución | |---|---|---| | `El stack g214-datalake-demo no existe en eu-north-1` al lanzar `./gestionar-nyc-taxi.sh crear` | El stack no existe o se creó en otra región (el script busca en `eu-north-1`) | Comprueba en CloudFormation (región Estocolmo) que existe; si no, vuelve a [04.01](../04.01-creardatalake/README.md) | | `No encuentro 2-athena-nyc-taxi.sql` | Estás fuera de la carpeta y el fichero no está junto al script | `cd 04.03-nyctaxi` y repite | | `El mes YYYY-MM aún no está publicado (error 403 o 404)` | Ese mes aún no lo ha publicado la ciudad de Nueva York | Usa meses más antiguos: `./gestionar-nyc-taxi.sh crear --meses "2025-09 2025-08"` (los meses anteriores del bucle ya se han subido) | | `No he podido descargar ...` o `no es un Parquet válido` | Red con filtro web o corte de conexión (a veces el filtro devuelve una página de error en vez del fichero) | Repite `crear`; si persiste, hazlo desde CloudShell | | Una tabla NYC devuelve 0 filas | Faltan particiones por registrar, o consultas un año/mes no cargado | `MSCK REPAIR TABLE demo_datalake_db.nyc_taxi_yellow_raw;` y `SHOW PARTITIONS` | | Una consulta `SELECT *` sin `LIMIT` tarda minutos y la consola no pinta todo | Athena guarda todas las filas como un CSV de varios GB en `athena-results/` | Es lo esperado en la presentación; borra ese fichero después (paso 4) | | `Permission denied` al ejecutar el script | El zip creado en Windows no guarda el permiso de ejecución | `chmod +x *.sh`, o `bash ./gestionar-nyc-taxi.sh crear` | | `bad interpreter` o `$'\r': command not found` | El zip creado en Windows ha dejado finales de línea de Windows (CRLF) | `sed -i 's/\r$//' *.sh` y repite | | `MALFORMED_QUERY` / `Only one sql statement is allowed` al pegar un `.sql` | Hay un comentario `-- ...` detrás de un `;` en la misma línea | Pon el comentario en la línea de encima o bórralo; ejecuta de una en una | ## Limpieza Solo lo de esta actividad, en este orden (el stack NO se borra aquí: se borra al final del Tema 4 desde [04.01](../04.01-creardatalake/README.md), y debe ser lo último). **Ojo: [04.06](../04.06-optimizarpresupuesto/README.md) y [04.07](../04.07-PanelStreamlitSeguridad.md) usan las tablas y los datos de NYC; si vas a hacerlas, no borres nada de aquí todavía.** 1. Con el script, desde esta carpeta: ```bash ./gestionar-nyc-taxi.sh eliminar ``` (o la opción `3` del menú). Lista lo que ha creado el ejercicio y te pide confirmar con `s` (`--si` para no preguntar). Borra: las tablas `nyc_taxi_yellow_curated` (con sus ficheros Parquet de `athena-results/tables/`) y `nyc_taxi_yellow_raw`, la vista `v_nyc_taxi_yellow` y los datos de `raw/nyc_taxi/` (todas las versiones de los ficheros). Al final verifica y lista lo que quede. No toca el stack, ni las tablas de la actividad 04.06 (`nyc_taxi_csv`, `viajes_compacto`, que tienen su propia limpieza), ni nada de otros ejercicios. Si no hay nada, lo dice y termina bien: se puede repetir. Para ver antes qué hay: `./gestionar-nyc-taxi.sh estado`. 2. Borra el CSV gigante de resultados si hiciste el `SELECT *` sin `LIMIT` del paso 4 (`aws s3 rm "s3://$BUCKET/athena-results/.csv"`): el script no lo conoce porque lo crea Athena con un identificador al azar. 3. Si vas a borrar el stack, no hace falta nada de esto: todo se va con él. (El script ya no deja ficheros descargados en CloudShell; si vienes de una versión antigua, `rm -rf /tmp/cunef_nyc_taxi`.) ## Cómo sabes que has terminado - [ ] `aws glue get-tables --database-name demo_datalake_db --region eu-north-1 --query "TableList[].Name"` lista `nyc_taxi_yellow_raw`, `v_nyc_taxi_yellow` y `nyc_taxi_yellow_curated` (y `./gestionar-nyc-taxi.sh estado` dice que el script ya ha hecho su trabajo). - [ ] `SHOW PARTITIONS` muestra una partición por mes cargado. - [ ] Has ejecutado y entendido las consultas de la presentación y tus cifras coinciden con las del paso 6. - [ ] Sabes decir qué método de pago deja más propina (la tarjeta) y por qué ese dato engaña (el efectivo no registra la propina). Anterior: [04.02 Titanic](../04.02-titanic/README.md) · Siguiente: [04.04 Calidad del aire de Madrid](../04.04-airemadrid/README.md)