Skip to content
English
On this page

Ejercicio: Dashboard de Análisis de Ventas con QuickSight y Athena

Parte 1: Configuración y Preparación de Datos

Escenario

Implementaremos un dashboard de análisis de ventas que incluirá:

  • Datos almacenados en S3
  • Consultas con Amazon Athena
  • Visualizaciones con QuickSight
  • Actualizaciones automáticas

Estructura del Proyecto

sales-analytics/
├── data/
│   ├── raw/
│   │   └── sales_data.csv
│   └── processed/
│       └── transformed_sales.csv

├── sql/
│   ├── create_database.sql
│   ├── create_tables.sql
│   └── analysis_queries/
│       ├── daily_sales.sql
│       ├── product_performance.sql
│       └── regional_analysis.sql

├── scripts/
│   ├── data_preparation/
│   │   ├── transform_data.py
│   │   └── upload_to_s3.py
│   │
│   ├── athena/
│   │   ├── setup_athena.py
│   │   └── verify_queries.py
│   │
│   └── quicksight/
│       ├── create_dataset.py
│       └── setup_permissions.py

├── config/
│   ├── athena_config.json
│   └── quicksight_config.json

└── README.md

1. Preparación de Datos

1.1 Estructura del CSV de Ventas

csv
transaction_id,date,product_id,product_name,category,quantity,unit_price,total_amount,region,store_id
1001,2024-01-01,P001,Laptop X1,Electronics,1,999.99,999.99,North,ST001
1002,2024-01-01,P002,Mouse Pro,Accessories,2,29.99,59.98,South,ST002

1.2 Script de Transformación

python
# scripts/data_preparation/transform_data.py
import pandas as pd
import numpy as np

def transform_sales_data(input_file, output_file):
    # Leer datos
    df = pd.read_csv(input_file)
    
    # Agregar columnas calculadas
    df['year'] = pd.to_datetime(df['date']).dt.year
    df['month'] = pd.to_datetime(df['date']).dt.month
    df['profit_margin'] = df['total_amount'] * 0.15
    
    # Limpiar datos
    df = df.dropna()
    df = df[df['total_amount'] > 0]
    
    # Guardar datos transformados
    df.to_csv(output_file, index=False)

if __name__ == "__main__":
    transform_sales_data(
        'data/raw/sales_data.csv',
        'data/processed/transformed_sales.csv'
    )

1.3 Script de Carga a S3

python
# scripts/data_preparation/upload_to_s3.py
import boto3
import os

def upload_to_s3(file_path, bucket_name, s3_key):
    s3 = boto3.client('s3')
    try:
        s3.upload_file(file_path, bucket_name, s3_key)
        print(f"Successfully uploaded {file_path} to {bucket_name}/{s3_key}")
    except Exception as e:
        print(f"Error uploading file: {str(e)}")

if __name__ == "__main__":
    upload_to_s3(
        'data/processed/transformed_sales.csv',
        'my-sales-analytics-bucket',
        'data/sales/transformed_sales.csv'
    )

2. Configuración de Athena

2.1 Crear Base de Datos

sql
-- sql/create_database.sql
CREATE DATABASE IF NOT EXISTS sales_analytics;

2.2 Crear Tabla

sql
-- sql/create_tables.sql
CREATE EXTERNAL TABLE IF NOT EXISTS sales_analytics.sales (
    transaction_id STRING,
    date DATE,
    product_id STRING,
    product_name STRING,
    category STRING,
    quantity INT,
    unit_price DECIMAL(10,2),
    total_amount DECIMAL(10,2),
    region STRING,
    store_id STRING,
    year INT,
    month INT,
    profit_margin DECIMAL(10,2)
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE
LOCATION 's3://my-sales-analytics-bucket/data/sales/'
TBLPROPERTIES ('skip.header.line.count'='1');

2.3 Script de Configuración de Athena

python
# scripts/athena/setup_athena.py
import boto3
import time

def setup_athena():
    athena = boto3.client('athena')
    
    # Crear base de datos
    with open('sql/create_database.sql', 'r') as f:
        create_db_query = f.read()
    
    # Ejecutar query
    response = athena.start_query_execution(
        QueryString=create_db_query,
        ResultConfiguration={
            'OutputLocation': 's3://my-sales-analytics-bucket/athena-results/'
        }
    )
    
    # Esperar a que termine
    while True:
        status = athena.get_query_execution(
            QueryExecutionId=response['QueryExecutionId']
        )['QueryExecution']['Status']['State']
        
        if status in ['SUCCEEDED', 'FAILED', 'CANCELLED']:
            break
        time.sleep(1)
    
    # Crear tabla
    with open('sql/create_tables.sql', 'r') as f:
        create_table_query = f.read()
    
    athena.start_query_execution(
        QueryString=create_table_query,
        ResultConfiguration={
            'OutputLocation': 's3://my-sales-analytics-bucket/athena-results/'
        }
    )

if __name__ == "__main__":
    setup_athena()

3. Consultas de Análisis

3.1 Ventas Diarias

sql
-- sql/analysis_queries/daily_sales.sql
SELECT
    date,
    SUM(total_amount) as daily_sales,
    COUNT(DISTINCT transaction_id) as transaction_count,
    SUM(profit_margin) as daily_profit
FROM
    sales_analytics.sales
GROUP BY
    date
ORDER BY
    date;

3.2 Rendimiento de Productos

sql
-- sql/analysis_queries/product_performance.sql
SELECT
    product_name,
    category,
    SUM(quantity) as total_units,
    SUM(total_amount) as total_revenue,
    AVG(unit_price) as avg_price,
    SUM(profit_margin) as total_profit
FROM
    sales_analytics.sales
GROUP BY
    product_name,
    category
ORDER BY
    total_revenue DESC;

Verificación Parte 1

1. Verificar Datos

  • [ ] CSV procesado correctamente
  • [ ] Datos cargados en S3
  • [ ] Formato de datos correcto

2. Verificar Athena

  • [ ] Base de datos creada
  • [ ] Tabla creada
  • [ ] Consultas funcionando

3. Verificar Permisos

  • [ ] Acceso a S3 configurado
  • [ ] Permisos de Athena correctos
  • [ ] Ubicación de resultados accesible

Troubleshooting Común

Errores de Datos

  1. Verificar formato CSV
  2. Revisar transformaciones
  3. Verificar carga en S3

Errores de Athena

  1. Verificar sintaxis SQL
  2. Revisar permisos
  3. Verificar ubicación de datos

Errores de Permisos

  1. Verificar rol IAM
  2. Revisar políticas de bucket
  3. Verificar configuración de Athena

Parte 2: Configuración de QuickSight y Visualizaciones

1. Configuración de QuickSight

1.1 Configurar Permisos de QuickSight

python
# scripts/quicksight/setup_permissions.py
import boto3
import json

def setup_quicksight_permissions():
    quicksight = boto3.client('quicksight')
    
    # Configurar acceso a Athena
    response = quicksight.update_data_source_permissions(
        AwsAccountId='YOUR_ACCOUNT_ID',
        DataSourceId='sales-analytics-source',
        GrantPermissions=[
            {
                'Principal': 'arn:aws:quicksight:region:account:user/default/admin',
                'Actions': [
                    'quicksight:UpdateDataSourcePermissions',
                    'quicksight:DescribeDataSource',
                    'quicksight:DescribeDataSourcePermissions',
                    'quicksight:PassDataSource',
                    'quicksight:UpdateDataSource',
                    'quicksight:DeleteDataSource'
                ]
            }
        ]
    )

1.2 Crear Conjunto de Datos

python
# scripts/quicksight/create_dataset.py
def create_sales_dataset():
    quicksight = boto3.client('quicksight')
    
    # Crear conjunto de datos físico
    response = quicksight.create_data_set(
        AwsAccountId='YOUR_ACCOUNT_ID',
        DataSetId='sales-analytics-dataset',
        Name='Sales Analytics Dataset',
        PhysicalTableMap={
            'sales': {
                'CustomSql': {
                    'DataSourceArn': 'arn:aws:quicksight:region:account:datasource/sales-analytics-source',
                    'Name': 'Sales Data',
                    'SqlQuery': '''
                        SELECT *
                        FROM sales_analytics.sales
                        WHERE year >= 2024
                    ''',
                    'Columns': [
                        {'Name': 'transaction_id', 'Type': 'STRING'},
                        {'Name': 'date', 'Type': 'DATETIME'},
                        {'Name': 'product_name', 'Type': 'STRING'},
                        {'Name': 'total_amount', 'Type': 'DECIMAL'},
                        {'Name': 'region', 'Type': 'STRING'}
                    ]
                }
            }
        },
        ImportMode='SPICE',
        Permissions=[
            {
                'Principal': 'arn:aws:quicksight:region:account:user/default/admin',
                'Actions': [
                    'quicksight:UpdateDataSetPermissions',
                    'quicksight:DescribeDataSet',
                    'quicksight:DescribeDataSetPermissions',
                    'quicksight:PassDataSet',
                    'quicksight:UpdateDataSet',
                    'quicksight:DeleteDataSet'
                ]
            }
        ]
    )

2. Creación de Visualizaciones

2.1 Dashboard Principal

json
// config/dashboard_config.json
{
    "dashboardName": "Sales Analytics Dashboard",
    "sheets": [
        {
            "name": "Sales Overview",
            "visualizations": [
                {
                    "title": "Daily Sales Trend",
                    "type": "LineChart",
                    "dimensions": ["date"],
                    "measures": ["total_amount"]
                },
                {
                    "title": "Sales by Region",
                    "type": "PieChart",
                    "dimensions": ["region"],
                    "measures": ["total_amount"]
                },
                {
                    "title": "Top Products",
                    "type": "BarChart",
                    "dimensions": ["product_name"],
                    "measures": ["total_amount"],
                    "sortBy": "total_amount",
                    "limit": 10
                }
            ]
        }
    ]
}

2.2 Script de Automatización de Dashboard

python
# scripts/quicksight/create_dashboard.py
import boto3
import json

def create_dashboard():
    quicksight = boto3.client('quicksight')
    
    # Cargar configuración
    with open('config/dashboard_config.json', 'r') as f:
        config = json.load(f)
    
    # Crear análisis
    analysis_response = quicksight.create_analysis(
        AwsAccountId='YOUR_ACCOUNT_ID',
        AnalysisId='sales-analysis',
        Name=config['dashboardName'],
        Permissions=[
            {
                'Principal': 'arn:aws:quicksight:region:account:user/default/admin',
                'Actions': [
                    'quicksight:RestoreAnalysis',
                    'quicksight:UpdateAnalysisPermissions',
                    'quicksight:DeleteAnalysis',
                    'quicksight:QueryAnalysis',
                    'quicksight:DescribeAnalysis',
                    'quicksight:UpdateAnalysis'
                ]
            }
        ],
        SourceEntity={
            'SourceTemplate': {
                'DataSetReferences': [
                    {
                        'DataSetPlaceholder': 'sales_data',
                        'DataSetArn': 'arn:aws:quicksight:region:account:dataset/sales-analytics-dataset'
                    }
                ],
                'Arn': 'arn:aws:quicksight:region:account:template/sales-template'
            }
        }
    )

3. Configuración de Actualizaciones Automáticas

3.1 Configurar Refresh Schedule

python
# scripts/quicksight/setup_refresh.py
def setup_refresh_schedule():
    quicksight = boto3.client('quicksight')
    
    response = quicksight.update_data_set_refresh_schedule(
        AwsAccountId='YOUR_ACCOUNT_ID',
        DataSetId='sales-analytics-dataset',
        Schedule={
            'RefreshType': 'INCREMENTAL_REFRESH',
            'ScheduleFrequency': 'DAILY',
            'StartTime': '02:00',
            'TimeZone': 'UTC'
        }
    )

3.2 Configurar Notificaciones

python
# scripts/quicksight/setup_notifications.py
def setup_refresh_notifications():
    sns = boto3.client('sns')
    
    # Crear tópico SNS
    topic_response = sns.create_topic(Name='quicksight-refresh-notifications')
    
    # Configurar suscripción
    sns.subscribe(
        TopicArn=topic_response['TopicArn'],
        Protocol='email',
        Endpoint='admin@company.com'
    )

4. Pruebas y Validación

4.1 Script de Validación

python
# scripts/quicksight/validate_dashboard.py
def validate_dashboard():
    quicksight = boto3.client('quicksight')
    
    # Verificar dataset
    dataset_response = quicksight.describe_data_set(
        AwsAccountId='YOUR_ACCOUNT_ID',
        DataSetId='sales-analytics-dataset'
    )
    
    # Verificar dashboard
    dashboard_response = quicksight.describe_dashboard(
        AwsAccountId='YOUR_ACCOUNT_ID',
        DashboardId='sales-dashboard'
    )
    
    # Verificar permisos
    permissions_response = quicksight.describe_dashboard_permissions(
        AwsAccountId='YOUR_ACCOUNT_ID',
        DashboardId='sales-dashboard'
    )
    
    return {
        'dataset_status': dataset_response['DataSet']['Status'],
        'dashboard_status': dashboard_response['Dashboard']['Version']['Status'],
        'permissions': permissions_response['Permissions']
    }

Verificación Final

1. Verificar QuickSight

  • [ ] Conjunto de datos creado
  • [ ] Visualizaciones funcionando
  • [ ] Permisos configurados
  • [ ] Actualizaciones programadas

2. Verificar Dashboard

  • [ ] Todas las visualizaciones cargan
  • [ ] Filtros funcionando
  • [ ] Interactividad correcta
  • [ ] Datos actualizados

3. Verificar Automatización

  • [ ] Refresh automático funcionando
  • [ ] Notificaciones llegando
  • [ ] Errores registrados
  • [ ] Performance aceptable

Troubleshooting Común

Errores de QuickSight

  1. Verificar permisos de dataset
  2. Revisar consultas SQL
  3. Verificar límites de SPICE

Errores de Visualización

  1. Verificar tipos de datos
  2. Revisar cálculos
  3. Verificar formato de fechas

Errores de Actualización

  1. Verificar configuración de refresh
  2. Revisar logs de errores
  3. Verificar capacidad SPICE

Mejores Prácticas

  1. Optimización de Consultas
sql
-- Ejemplo de consulta optimizada
SELECT
    DATE_TRUNC('day', date) as sale_date,
    SUM(total_amount) as daily_total
FROM
    sales_analytics.sales
GROUP BY
    DATE_TRUNC('day', date)
  1. Configuración de Caché
python
# Configurar caché de SPICE
quicksight.update_data_set(
    AwsAccountId='YOUR_ACCOUNT_ID',
    DataSetId='sales-analytics-dataset',
    ImportMode='SPICE',
    PhysicalTableMap={...},
    LogicalTableMap={...},
    OutputColumns=[...]
)
  1. Manejo de Parámetros
python
# Configurar parámetros de dashboard
dashboard_parameters = {
    'TimeRange': {
        'Name': 'TimeRange',
        'Values': ['Last 30 Days', 'Last 90 Days', 'Year to Date'],
        'DefaultValue': 'Last 30 Days'
    }
}

Limpieza

  1. Eliminar datasets de QuickSight
  2. Eliminar dashboards
  3. Revocar permisos
  4. Eliminar programaciones
  5. Limpiar caché SPICE

Puntos Importantes

  1. QuickSight utiliza SPICE para optimización
  2. La actualización incremental es más eficiente
  3. Los permisos son críticos para la seguridad
  4. El monitoreo ayuda a prevenir problemas

Este ejercicio completo te permite:

  1. Configurar visualizaciones interactivas con QuickSight
  2. Integrar datos de Athena
  3. Automatizar actualizaciones
  4. Implementar mejores prácticas de visualización

Puntos clave para recordar:

  • SPICE es el motor en memoria de QuickSight
  • Las actualizaciones pueden ser incrementales
  • Los permisos deben configurarse correctamente
  • El monitoreo es esencial