Aaronnys Ortiz

Desarrollador Qlik Sense · Inteligencia de Negocios

Aaronnys Saúl Ortiz Molina

Analista de Inteligencia de Negocios en el Grupo DAABON, un grupo agroindustrial de 53 sociedades: plantaciones, plantas extractoras, una refinería, una zona franca y operación portuaria.

Tengo 23 informes de Qlik Sense Enterprise en producción a mi cargo. Trabajo el ciclo completo: conexiones ODBC y REST, script de carga, QVD, modelado en estrella, set analysis y diseño de tableros.

Santa Marta, Colombia · UTC−5 · Español nativo · Inglés B2

23
informes de Qlik Sense en producción a mi cargo
414 → 279 s
recarga de la aplicación más grande del entorno
11,1 → 4,5 M
filas de su modelo de datos
8 → 3
claves sintéticas en esa misma aplicación

Proyecto propio

RESUMEN — Aplicación de Qlik Sense, de la carga al tablero

Aplicación completa sobre una comercializadora agroexportadora, con datos sintéticos generados por el propio script de carga. Todas las imágenes son capturas de Qlik Sense.

Cubre el ciclo entero: generación del dato, modelo en estrella, calendario maestro, variables de aplicación, set analysis y cuatro hojas de análisis.

Volumen232.000 líneas de factura y 26.000 de presupuesto
ModeloEstrella: 1 tabla de hechos, 5 dimensiones y calendario maestro. 0 claves sintéticas, 0 lazos circulares
Recarga~6 segundos
Resumen comercial — captura de Qlik Sense

Resumen comercial

Seis KPI, la serie mensual contra presupuesto y contra el año anterior, participación por región y detalle por país.

  • Set analysis con año dinámico: el gráfico mensual toma el periodo de $(=Max(Anio)), de modo que la comparación sigue a la selección sin expresiones distintas por año.
  • Medidas centralizadas en variables de aplicación, reutilizadas por todos los objetos de las cuatro hojas.
  • Límite de dimensión por medida para el top de clientes, y etiquetas de serie calculadas por expresión.

Set analysis

// Barras: el año que mande la selección
Sum({<Origen={'Real'}, Anio={$(=Max(Anio))}>} Valor_USD)

// Línea de comparación: el año anterior a ese
Sum({<Origen={'Real'}, Anio={$(=Max(Anio)-1)}>} Valor_USD)
Presupuesto contra real — captura de Qlik Sense

Presupuesto contra real

Cumplimiento en valor y en volumen, desviación por línea con color condicional y tabla dinámica de línea por mes.

  • Presupuesto concatenado a la tabla de hechos con un campo Origen, en lugar de una tabla aparte. Real y presupuesto comparten calendario, producto y país sin generar claves sintéticas contra las tres dimensiones a la vez.
  • La separación entre los dos mundos es exclusivamente set analysis, así que un mismo filtro de región mueve las dos cifras.
  • Color por expresión sobre la desviación, y medidores con segmentos por umbral de cumplimiento.

Script y variables

// Script: el presupuesto se concatena al hecho
CONCATENATE (Hechos_Comercial)
LOAD  %LlaveProducto, %LlavePais,
      Date(MakeDate(Anio_Ppto, Mes_Ppto, 1))  as Fecha,
      'Presupuesto'                           as Origen,
      ...

// Variables de aplicación
vVentaReal     = (Sum({<Origen={'Real'}>}        Valor_USD))
vVentaPpto     = (Sum({<Origen={'Presupuesto'}>} Valor_USD))
vCumplimiento  = ($(vVentaReal) / $(vVentaPpto))
Clientes y margen — captura de Qlik Sense

Clientes y margen

Facturación y margen de los quince mayores clientes en un gráfico combinado de doble eje, altas y bajas de cartera por año, y detalle con variación interanual.

  • Comparación interanual recortada por el mismo mes de corte en los dos años, mediante una marca Es_Mes_YTD calculada en el calendario maestro.
  • Primer y último año de compra de cada cliente resueltos en el script con un LEFT JOIN agregado, no con set analysis: no dependen de la selección y no se recalculan en cada interacción.
  • Participación sobre el total con TOTAL, evitando agregaciones anidadas.

Script y variables

// Script: lo que no depende de la selección
LEFT JOIN (Clientes)
LOAD  %LlaveCliente,
      Min(Year(Fecha)) as Anio_Primera_Compra,
      Max(Year(Fecha)) as Anio_Ultima_Compra
RESIDENT Hechos_Comercial  WHERE Origen = 'Real'
GROUP BY %LlaveCliente;

// Los dos años recortados por el mismo mes
vVentaYTD          = (Sum({<Origen={'Real'}, Anio={$(=Max(Anio))},   Es_Mes_YTD={1}>} Valor_USD))
vVentaYTDAnterior  = (Sum({<Origen={'Real'}, Anio={$(=Max(Anio)-1)}, Es_Mes_YTD={1}>} Valor_USD))
Control de carga — captura de Qlik Sense

Control de carga

Filas cargadas por origen, rango de fechas, cuadre por año y precio medio por línea.

  • Tabla de auditoría calculada en el propio script después de cargar los hechos: filas por origen, fecha mínima y máxima y valor total.
  • Deja la recarga cuadrada sin salir de la aplicación: una carga incompleta se ve en la hoja en lugar de detectarse cuando alguien reporta una cifra rara.

Script

Control_Carga:
LOAD  Origen           as Control_Origen,
      Count(Origen)    as Control_Filas,
      Date(Min(Fecha)) as Control_Fecha_Min,
      Date(Max(Fecha)) as Control_Fecha_Max,
      Round(Sum(Valor_USD)) as Control_Valor_USD
RESIDENT Hechos_Comercial
GROUP BY Origen;
Modelo de datos — captura de Qlik Sense

Modelo de datos

Visor del modelo de la propia aplicación: una tabla de hechos, cinco dimensiones y el calendario maestro.

  • Esquema en estrella sin tablas $Syn ni lazos circulares.
  • El país se resuelve en la carga con ApplyMap y cuelga de la tabla de hechos. Colgarlo a la vez del cliente y del hecho habría cerrado un lazo circular.
  • Llaves con prefijo % y campos descriptivos separados por dimensión.
Script de carga — captura de Qlik Sense

Script de carga

Ocho pestañas separadas por origen y por tabla.

  • Catálogos cargados primero, dejando su tabla de mapeo; la tabla de hechos resuelve todas sus llaves con ApplyMap y no usa ningún JOIN.
  • Preceding loads encadenados para calcular columna sobre columna sin tablas temporales.
  • Calendario maestro generado sobre el rango real de los hechos, no sobre fechas escritas a mano.

Grupo DAABON · 53 sociedades

Trabajo en producción

Seis intervenciones sobre informes en uso, con las cifras medidas antes y después. Sin capturas: estos informes contienen datos de clientes, nómina y comercio exterior.

Optimización de la aplicación más grande del entorno

Once dominios de negocio en una sola aplicación —P&G, costos, ventas, cartera, dos zonas francas, logística, ausentismo, PQRS y CRM—: 6.210 líneas de script en 39 pestañas, 74 tablas, 37 hojas y 708 objetos.

414 → 279 s
tiempo de recarga
11,1 → 4,5 M
filas del modelo (−60 %)
8 → 3
claves sintéticas
60 → 37
consultas al ERP por recarga
  • Documentación previa de la aplicación completa, incluidas sus 309 medidas, como base del trabajo.
  • Línea base de todas las medidas contra una copia sin modificar, comparada después de cada paso: 309 de 334 medidas idénticas, 0 errores.
  • Sustitución de siete aperturas por recarga de un Excel compartido por los QVD de una aplicación extractora, previa verificación de que los formatos de fecha de ambos scripts coincidían hoja por hoja.
  • Corrección de un presupuesto de costos incompleto en 240.405 millones de pesos, causado por un Left Join que multiplicaba filas y un LOAD DISTINCT que colapsaba líneas. Cuadrado contra los QVD de origen.
  • Las tres claves sintéticas restantes quedaron documentadas: sostienen defectos de datos de sistemas de origen y resolverlas mueve cifras publicadas.

Recuperación de un informe que nunca había logrado recargar

Aplicación de Desarrollo Humano publicada y en uso, con datos congelados. La recarga manual moría a los 261 segundos.

1 columna
origen del bloqueo
325 s
recarga completa
387 M
filas leídas
192
expresiones sin error
  • Dos pestañas solicitaban las 39 columnas de una vista del ERP; una de ellas bloquea la consulta indefinidamente. Reducir el SELECT a las 8 columnas que el LOAD utilizaba resolvió el bloqueo.
  • Seis correcciones de negocio adicionales, todas medidas: una lista de festivos sin efecto (4.261 → 3.938 personas fuera de meta), dos rangos sin tramo que dejaban 635 personas en nulo, una sociedad sin grupo asignado (3.647 → 4.887 en Cultivo) y una columna vacía.
  • Cada corrección registrada con la cifra anterior y la posterior en el historial del informe.

Diagnóstico de QVD solapados en una cadena de extracción

Cuatro informes consumen los QVD que deja una aplicación extractora. Los archivos anuales se solapaban.

70.058 filas
para 34.961 manifiestos
4
informes afectados
35.029
filas duplicadas de un año
  • El origen construye la URL de la API con una operación aritmética sobre la fecha, de modo que el rango solicitado no corresponde al del archivo generado.
  • Impacto medido: dos informes con un año duplicado y otros dos recibiendo ese año desde un archivo con otro nombre.
  • Documentado con las cifras para planificar la corrección en el origen, que es una aplicación publicada de la que dependen cuatro informes.

Reducción de una cadena de carga sobre encuestas de clima

Aplicación de gestión de personas sin recargar durante tres meses. El bloque de clima laboral leía cinco tablas de encuestas completas.

412.836
encuestas leídas enteras
4,9 M
respuestas
6,1 M
filas intermedias
3
pestañas con la misma cadena
  • Filtrado en el origen en lugar de agregar después, sin modificar la lógica: los indicadores mantienen su valor.
  • Diagnóstico del bloqueo de fondo: un conector REST apuntando a una versión anterior del ERP que devuelve 401, contenido con ErrorMode = 0.
  • Tabla de estado de carga añadida para que ese error deje de ser silencioso.

Corrección de la llave persona-mes del informe de rotación

El informe mostraba el mes en curso sin retiros. La llave que asocia los retiros al panel persona-mes estaba mal construida.

0 → 13.546
retiros asociados
0 → 1.125
retiros del mes en curso
554.349
filas persona-mes del panel
  • Reconstrucción de la llave y verificación sobre la copia de trabajo antes de publicar.
  • Auditoría del evento objetivo: de 7.048 «renuncias voluntarias» reportadas por el origen, 325 eran traslados entre sociedades del mismo grupo. Cambiar la llave del episodio de empleo del número de nómina a la cédula lo corrige.
  • Sobre ese panel se construyó después un modelo de riesgo de renuncia voluntaria con 86 variables y 6.404 eventos (Python, análisis de supervivencia en tiempo discreto).

Estado de resultados de un área reproducido en Qlik

Un área llevaba su P&G en Excel, con su formato, sus negritas y sus totales desplegables, y necesitaba verlo en Qlik sin perder esa presentación.

18 de 18
filas cuadradas al peso
7
columnas: real, presupuesto y año anterior
0
importes sin clasificar
  • Hoja construida con una extensión de tabla que reproduce el formato del Excel del área: colores, negritas y el total de cada grupo con su detalle desplegable.
  • Clasificación de cuentas resuelta por búsqueda directa sobre el adjunto del área, sin tocar la cascada de mapeos existente, de la que dependen otras dos hojas.
  • Cuadre fila por fila contra el Excel del mes, en real y en presupuesto, y comparación adicional contra el año anterior.

Método

Prácticas aplicadas

La mayoría de los 23 informes llegaron construidos por otras personas. Estas son las prácticas con las que los mantengo.

Control de versiones por informe

Cada informe tiene su ficha de contexto, su script troceado por pestañas y versionado en Git, y el registro de qué área pidió cada cambio. Revertir una petición es una operación de Git.

Separación entre publicada y copia de trabajo

Los cambios se hacen sobre una copia, se comparan contra la aplicación publicada y se publican cuando las cifras cuadran. Las copias de respaldo están marcadas y protegidas contra escritura.

Línea base antes y después

Antes de modificar nada se captura el valor de todas las medidas de la aplicación; al terminar se vuelve a capturar y se comparan. Es lo que permite optimizar un modelo sin mover un indicador.

Automatización de la operación

Node.js contra la Engine API por websocket para leer y escribir script, hojas y objetos, y contra el Repository Service por REST para lo administrativo.

Documentación de decisiones

Los mensajes de commit registran el motivo del cambio, y cada informe mantiene una lista de lo que queda abierto con su diagnóstico.

Perfil técnico

Capacidades

Qlik Sense EnterpriseQlik Sense Enterprise on Windows, ~4 años. 23 informes en producción a mi cargo.
Conexión a orígenes de datosODBC contra ERP y base de nómina, conectores REST, carpetas de red, Excel, SharePoint / Office 365, Google Drive y SAP OData.
ModeladoEsquema en estrella, calendario maestro, resolución de claves sintéticas y lazos circulares, tablas de enlace.
Scripting y QVDAplicaciones extractoras que alimentan a otros informes, carga incremental y catálogo de 419 QVD de la biblioteca leyendo solo cabeceras.
Set analysisIdentificadores y modificadores, P() y E(), TOTAL, Aggr, comparaciones interanuales comparables.
Diseño de tablerosKPI, gráficos combinados de doble eje, tablas dinámicas, medidores, color por expresión y paneles de filtros.
Dominios de negocioRotación, nómina, clima laboral, P&G, cartera, logística, comercio exterior y PQRS.
AutomatizaciónEngine API (enigma.js) y Repository Service desde Node.js: script, hojas, objetos y líneas base de medidas.
Datos y modelado estadísticoSQL sobre tablas de millones de filas. Python: pandas, scikit-learn, statsmodels, lifelines, LightGBM y SHAP.

Qlik Sense

  • LOAD, RESIDENT, JOIN, CONCATENATE, MAPPING y ApplyMap
  • Preceding loads y sentencias de control
  • Set analysis, P() y E(), TOTAL, Aggr
  • Modelo en estrella y calendario maestro
  • QVD, extractoras y carga incremental
  • Variables de aplicación y color por expresión
  • Engine API (enigma.js) y Repository Service (QRS)

Datos

  • SQL (PostgreSQL, SQLite)
  • ODBC y conectores REST
  • Python: pandas, scikit-learn, statsmodels, lifelines, LightGBM, SHAP
  • Análisis de supervivencia en tiempo discreto
  • Excel

Desarrollo

  • JavaScript y Node.js
  • React (Vite, Tailwind)
  • Cloudflare Workers, D1, KV y R2
  • Git

Contacto

Aaronnys Saúl Ortiz Molina

Desarrollador Qlik Sense · Inteligencia de Negocios · Santa Marta, Colombia · UTC−5 · Español nativo · Inglés B2