3 Cosas de Pentaho Data Integration que me hubiera gustado saber desde un principio

No recuerdo exactamente la fecha en que empecé a trabajar con Kettle, ahora llamado Pentaho Data Integration (PDI), para realizar tareas de ETL. Estimo que fue por el 2007 en que conocí tan útil herramienta con la cual al día de hoy me apoyo para realizar innumerable cantidad de tareas, o algoritmos de validación, que me tomaría mucho mas tiempo implementar, depurar y modificar, si lo realizara, por ejemplo, en Java.

Como todo proceso de aprendizaje, estuve expuesto a días de dolores de cabeza tratando de comprender qué estaba haciendo mal cuando PDI, por algún motivo, no realizaba lo que, según mi diseño, debería hacer. A continuación muestro algunas situaciones de las que debes estar pendiente al momento de trabajar con Strings y datos numéricos, que en su momento, aprendí algunas con ayuda de Google, y otras por ensayo y error:

Decirle a PDI que un String en null difiere de un String vacío

¿No les ha pasado que tienen una transformación en la que se leen datos de tipo VARCHAR o TEXT (y que PDI entiende como String) de una fuente sobre la cual en algún paso realizan una comparación, y que por algún motivo, la salida no es la esperada?

Por algún motivo que desconozco, los desarrolladores de PDI encontraron divertido hacer que durante una transformación, un String vacío, sea igual a null.

Este parámetro en particular se vuelve un verdadero problema cuando utilizas una User Defined Class donde esperas capturar alguna excepción de tipo NullPointerException para tomar una decisión en tu script.

Para quienes tengan transformaciones donde la sensibilidad a los datos (y sus metadatos) sea alta, lo mejor es habilitar esta opción.

Para esto, desde la barra de herramientas de PDI, elige Edit -> Edit the kettle.properties file. Busca la variable KETTLE_EMPTY_STRING_DIFFERS_FROM_NULL y coloca ‘Y’, sin las comillas, como valor.

Kettle Properties

Quitar espacios en blanco

Otra buena práctica al trabajar con Strings, consiste en eliminar los espacios en blancos que pueden añadirse al final y que son autogenerados por algunos manejadores de base de datos, y hasta el mismo PDI, en pasos como el de Concat Fields.

Para esto, utiliza el paso String Operations y en ‘Trim type’ elige ‘both’. Sugiero realices esto antes de tener que usar el valor en algún paso como Filter Rows.

String Operations

Pérdida de precisión en variables numéricas

Se debe tener mucho cuidado y atención al momento de trabajar con valores numéricos, sobretodo cuando están sometidos a cálculos en muchos pasos en una transformación.

PDI maneja tres tipos de datos numéricos: Number, BigNumber e Integer. En el primero se mapean automáticamente cualquier valor que tenga parte decimal, en caso contrario, el valor será mapeado como Integer. Se debe tener atención en las siguientes situaciones:

– Si multiplicas un valor Number por Integer, automáticamente pierdes la precisión decimal. Si el factor entero es una constante, entonces puedes especificarla como decimal.

– Procura siempre que trabajes con valores de tipo de dato Number, establecer su formato y cual es el signo de agrupación y el signo decimal. Esto último es súper importante cuando trabajas con fuentes de datos heterogéneas con codificaciones regionales distintas (ejemplo, una base de datos y una hoja de excel). Tener esto como práctica te ahorrará mucho sdolores de cabeza y tiempo.

Por ejemplo, la siguiente transformación modifica un valor numérico que representa un descuento otorgado, sin embargo, cuando el registro es una nota de crédito, este descuento debe ser eliminado.

Ejemplo Kettle Number 1

Se utiliza entonces un Filter Rows para especificar una constante que podrá ser 0.0 o 1.0. Preste atención en que se ha especificado el typo, formato y signos.

Ejemplo Kettle Number 2

Ejemplo Kettle Number 3

Posteriormente, un paso Calculator asigna a un campo nuevo llamado “Descuento”, el resultado de multiplicar la constante definida “ES_NC” por el atributo “Monto_Facturado”. El tipo de valor y signos es especificado nuevamente, por buena práctica. El formato puede ser cambiado si así se desea, en ‘Conversion mask’.

Ejemplo Kettle Number 4

En un próximo post, hablaré de simples trucos y configuraciones, que harán que las transformaciones se ejecuten más rápido. También, tengo interés en realizar uno o varios posts dedicados al paso User Defined Class, para aquellos valientes que quieren hacer mucha mas magia con PDI.

¡Hasta pronto!

Obtén retroalimentación y comentarios de tu cliente o jefe y difunde ideas acerca de tus layouts y diseños con Bounceapp

En esta oportunidad les presento esta práctica aplicación web que nos permitirá con tan solo 3 pasos recopilar en un solo sitio todos los comentarios e ideas que puedan ofrecernos nuestros jefes, clientes o compañeros de trabajo acerca del diseño visual de ese portal o aplicación web en la que estamos trabajando.

Todo funciona de la siguiente manera:

1. Abre www.bounceapp.com e inserta la url que dirige a la pantalla de la cual quieres obtener comentarios e ideas. Presiona ‘Grab Screenshot’ y mientras la aplicación genera una captura completa de la página, puedes ver y jugar con una pelota de ping pong que no dejará de rebotar. De ahí el nombre del sitio… duh!

001

2. Una vez que termine el procesamiento, tendrás la captura completa de la página de principio a fin. En ella puedes ahora remarcar zonas y dejar comentarios al respecto. Puedes colocar notas como ‘Revisa esto’, ‘¿Que tal la paleta de colores empleadas?’ o lo que se te ocurra.

003

3. En la esquina superior derecha presiona el botón que generará una breve URL que podrás enviar por correo a quienes desees, publicarlo en Twitter o en Facebook. Cualquiera que ingrese podrá hacer sus propias anotaciones y cada vez que revises el enlace, verás los comentarios que en ella han hecho.

El portal cuenta también con servicios avanzados para empresas que te permiten registrar un dominio y almacenar cientos de capturas y otros servicios, pero para discusiones informales vía web esta forma es mucho mejor que tomar manualmente capturas de pantalla, editarlas y enviarlas por correo.

“entre gustos y colores…”

image

Confieso que cuando se trata de elegir una paleta de colores para las aplicaciones que hago, tiendo a ser extremadamente simplista y elegir cuando mucho dos tonos de azul, gris y siempre el blanco. Tan simplista soy que cuando trabajo en mas de dos aplicaciones a la vez, tiendo a confundirlas pues siempre sigo el mismo diseño. Pero eso se acabó ayer! No sé cómo no conocía este portal.

Color Hunter es un buscador de paletas de colores sorprendente! Básicamente colocas las palabras claves que necesitas y haciendo uso de galerías públicas de Flickr realiza paletas de colores que combinan de un bien en la IU de tu aplicación.

No más azulitos ni escalas de grises para mí. Ya tengo de donde sacar colorcitos Lengua fuera

FileReference.download() falla, no descarga el archivo, no hace nada

A diferencia de una aplicación Adobe Air, cuando esta se compila en un archivo Flash (SWF), el método Download() de la clase FileReference despliega la ventana para almacenar el archivo pero este no es descargado, simplemente no ocurre nada.

Adobe sabe de este problema y lo postea acá: http://kb2.adobe.com/cps/363/3637d5c3.html

La solución es sencilla:

El método Download falla sólo cuando la clase FileReference es instanciada dentro de una función local. Para solucionar el problema basta con declararla de manera global. Ejemplos:

De esta forma el método Download no hará nada:

function downloadFile():void {
var fileRef:FileReference = new FileReference(); //FileReference com ámbito local
fileRef.download(new URLRequest(“myFile.txt”), “myFile.txt”);
}

De esta manera el método Download descargará el archivo y lo almacenará en el directorio elegido por el usuario:

private var fileRef:FileReference = new FileReference(); //FileReference com ámbito global
function downloadFile():void {
fileRef.download(new URLRequest(“myFile.txt”), “myFile.txt”);
}

Aplicando efectos a Labels, LinkButtons, Buttons, etc…

Si ya haz jugado con los efectos tan fácil de aplicar que tiene FLEX, te podrás haber dado cuenta que existen ciertos componentes que no “agarran” los efectos o no se animan. Esto ocurre cuando el componente es un Label (etiqueta) o en su defecto, posee un Label interno tal como un Button o un LinkButton. Por defecto, si aplicas un efecto a un Container (contenedor) todos sus hijos toman el efecto. Ejemplo, si creas un Canvas y le agregas un Label y un TextArea y le aplicas un efecto Fade (desvanecimiento) entonces cuando se este animando, solo el TextArea se verá desvanecer y el Label parecerá que aparece o se oculta de inmediato sin ese efecto transitorio de desvanecimiento.

Existen varios trucos para solventar esto. Uno es especificar literalmente a FLEX que tipo de fuente usará el Label. Es sencillo y se hace con una función setStyle pero por otro lado, tendrás que hacer lo mismo por cada Label, Button, …, que tengas en tu Container.

Acá propongo uno muy sencillo que te garantizará funcionar donde sea. Está en AS3. A nivel global creas un BlurFilter y un Array:

private var blur_filter:BlurFilter = new BlurFilter(0,0,0);
private var filtros:Array = new Array();

Luego, internamente en el código agregas el BlurFilter al Array:

filtros.push(blur_filter);

Y todo componente de FLEX tiene la propiedad filters. Bastará con asignar el Array filtros a la propiedad filter del Label, Button, LinkButton, …, para que mágicamente el texto de los Labels, o cualquier componente que tenga texo, se anime:

contenedor_u_objeto.filters = filtros;

Recuerda, basta con aplicar el filtro al contenedor, bien sea un Canvas, Panel, …, para que todos sus hijos se animen en conjunto sin importar que tipo de componentes sean 😛

Sentencia “WITH” para ahorrar código

Vaya que es tedioso cambiar el monton de propiedades de un objeto… Y FLEX suele prestarse para eso cuando se trabajan con estilos sin emplear CSS… Lo siguiente es un ejemplo de como usar la sentencia WITH para agrupar propiedades de un objeto.

Sin uso de la sentencia WITH un codigo en FLEX seria asi…

this.width = 600;
this.height = 300;
this.x = 800/2 – this.width/2;
this.y = 400/2 – this.height/2;
this.setStyle(“hideEffect”, this.parallel);
this.setStyle(“showEffect”, this.parallel);
this.bot_aceptar.label = “Aceptar”;

Usando WITH tendriamos algo menos amontonado…

with(this){
width = 600;
height = 300;
x = 800/2 – width/2;
y = 400/2 – height/2;
setStyle(“hideEffect”, parallel);
setStyle(“showEffect”, parallel);
bot_aceptar.label = “Aceptar”;
}

Security sandbox violation

Estaba haciendo una aplicación en FLEX que requiere el uso de AMFPHP para conectarme con una Base de Datos en Postgres y todo siempre funcionó bien, todo hasta que decidí acceder a mi aplicación desde una URL y no desde el .swf que se genera. El error descrito fue el siguiente:

Error #2044: Unhandled SecurityErrorEvent:. text=Error #2048: Security sandbox violation: http://localhost/SQR/bin-debug/SQR.swf cannot load data from http://127.0.0.1/amfphp/gateway.php.

Es un error muy común y fácil de solucionar. Se genera cuando una aplicación flash trata de acceder a datos que residen en otro dominio web. En mi caso, aunque no lo crean, es porque accedí a mi aplicacion desde mi servidor localhost y dentro de ella tengo un script que pide datos a un servicio bajo el dominio 127.0.0.1. Entonces se preguntaran, ¿no es localhost y 127.0.0.1 lo mismo?

Y mi respuesta es… “No necesariamente”. No es la primera vez que he tenidos problemas asi. Una vez, Windows dejó de reconocer el dominio localhost y debía acceder a mi servidor local siempre desde 127.0.0.1. La solución fue sencilla modificanddo un par de líneas en una subcarpeta de Windows -si ese es el caso de ustedes, googleenlo, es sencillo de resolver :P-

En el mejor de los casos, la solución se consigue cambiando todos los 127.0.0.1 por localhost o viceversa. Esto quiere decir que si en el AS3 tienes referencias a 127.0.0.1 entonces accede a tu aplicacion empleando la URL 127.0.0.1. Para cualquier IP o dominio aplica lo mismo.

En un entorno de producción real, esta modificacion ya no es viable. Para solucionarlo se crea un fichero en XML que va a permitir resolver el problema En este enlace Adobe publica la solución 🙂