Hitachi Vantara Pentaho Community Wiki
Child pages
  • Migrando Javascript de la versión 2.5.x a la 3.0.0
Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Current »

Introducción

Dado que el paso Javascript de Pentaho Data Integration puede contener prácticamente cualquier cosa y siendo que la antigua manera de hacer cualquier cosa fuera de lo común ya no funcionará, en el presente documento ofreceremos alternativas para conseguir sus objetivos.
El problema principal es que algunas de las operaciones especiales que se ejecutaban en Javascript requerían la API Java de Kettle. Esta API ha cambiado dramáticamente en la versión 3.0.

Modificando valores

En el pasado se permitía la modificación de valores en el lugar. Algunos métodos para lograrlo incluyen:

  • setValue()
  • str2dat()
  • dat2str()
  • str2num()
  • num2str();
  • ...

Todavía se permite la utilizaciónd estos métodos en el modo de compatibilidad. Sin embargo el resultado almacenado en el valor modificado será modificado al tipo de dato esperado.
Esta conversión de datos es transparente, ya que utiliza el motor de conversión de la versión 2.

Forzamos estas conversiones ya que en el pasado tipos de datos conflictivos causaban muchos problemas en transformaciones. Tener distintos tipos de datos en un mismo campo no es una situación deseable, ya que causa problemas durante la serialización de filas (Ordenar Filas, Ejecución en Cluster, Serializar a Archivo, ...) y durante la manipulación de bases de datos (Salida a Tabla, Búsqueda en BD, Unión en BD, Actualización, etc.)

Los problemas

Por ejemplo, miremos el ejercicio de conversión de datos:

dateField.dat2str("dd-MM-yyyy")

El tipo de dato del campo "dateField" es Date. El dato está siendo convertido internamente a String. De esta manera, el tipo de dato entra en conflicto con el tipo de dato esperado, "Date".
A causa de esto, antes de que el valor sea enviado a los próximos pasos, el tipo de dato es cambiado nuevamente de String a Date. Esto utiliza la máscara por defecto ("yyyy/MM/dd HH:mm:ss.SSS"), causando que la conversión falle.

El resultado será que "dateField" contendrá el valor nulo.

Otro ejemplo más sutil de conflictos de tipos de datos viene del hecho de que el motor Javascript no siempre utiliza el tipo de datos que uno espera. Por ejemplo, veamos la siguiente sentencia:

integerField.setValue(5);

Uno esperaría que el tipo de dato en la versión 2 sería un entero, cuando de hecho el motor de Javascript utiliza valores de punto flotante en todos lados.

Esto significa que el entero "integerField" mágicamente cambió a un tipo de dato "Number" en la versión 2. Eso causa a veces problemas en diferentes áreas.

En la versión 3, el tipo de dato será convertido nuevamente a entero. De todas maneras puede haber determinadas situaciones en las cuales se terminaría con un problema de conversión de datos.

La solución

La solución es siempre asegurarse de que se crean nuevos valores cuando se hacen conversiones de tipo. Otro consejo (como se muestra abajo) es dejar de utilizar el modo de compatibilidad.

De esta manera, la sentencia anterior se convierte en:

var stringField = date2str(dateField, "dd-MM-yyyy");

ó

var integerResult = 5;

Modo de compatibilidad

Por defecto el código Javascript antiguo correrá en modo de compatibilidad. Eso significa que el paso intentará comportarse como la versión antigua en la medida en que le sea posible.
Esto tendrá una pequeña consecuencia en el rendimiento debido al trabajo extra que esto requiere.
Si se desea utilizar la nueva arquitectura, puede deshabilitarse el modo de compatibilidad y cambiar código como éste:

  • intField.getInteger() --> intField
  • numberField.getNumber() --> numberField
  • dateField.getDate() --> dateField
  • bigNumberField.getBigNumber() --> bigNumberField
  • etc.

En lugar de utilizar los diferentes métodos Java, puede utilizarse la librería embebida. Encontrará también que el código resultante será más intuitivo.

Por ejemplo:

  • Comprobar valores nulos es ahora: field.isNull() --> field==null
  • Convertir String a Date: field.Clone().str2dat() --> str2date(field)
  • etc...

Si realiza estos cambios en el código puede lograr mejoras de rendimiento significativas.

Por favor tenga en cuenta de que ya no es posible la sobreescritura de valores utilizando los métodos. Esto es una decisión de diseño para asegurarse de que datos con un tipo de datos erróneo no terminen en las filas de salida del paso.
Esto era una posibilidad en la versión 2 y causaba problemas en algunas transformaciones en los pasos posteriores a un paso Javascript. En lugar de sobreescribir el contenido de los campos, cree nuevos campos utilizando la tabla al final del paso "Javascript Modificado". Luego asigne los valores a estos nuevos campos en el script, como si fueran variables.

Código Java y paquetes be.ibridge.kettle

Siendo que la API central de Pentaho Data Integration cambió, ya no es posible utilizar los paquetes be.ibridge.kettle mediante código Java embebido en el código Javascript.

Hay dos soluciones posibles a este problema:

Helper methods

La mejor manera de permanecer portable hacia el futuro es obviamente dejar de utilizar los paquetes Java internos de PDI en el código fuente.
Como puede verse en el capítulo siguiente "Añadiendo filas dinámicamente", se han expuesto nuevos métodos al motor Javascript para asistir en estos casos.

Por ejemplo::

  • Packages.be.ibridge.kettle.core.util.StringUtil.getVariable --> getVariable()
  • Packages.be.ibridge.kettle.core.util.StringUtil.setVariable --> setVariable()

Cambiar a los paquetes org.pentaho.di

Obviamente es aún posible (aunque no recomendable) utilizar la API interna de PDI. La mayoría de los métodos han permanecido sin modificaciones y sólo han sido movidos al esquema de nombres de org.pentaho.di.

Por ejemplo:

var cr = Packages.be.ibridge.kettle.core.Const.CR;

Changes to

var cr = Packages.org.pentaho.di.core.Const.CR;

Codificación y decodificación de cadenas en Base64


A pesar de que la librería par codificación y decodificación en Base64 de Apache Commons ya estaba disponible, el ejemplo de Base64 en la versión 2 utilizaba una clase de be.ibridge para hacer el trabajo.

En la versión 3 sugerimos utilice la excelente librería de Apache Commons, tal como se muestra en el ejemplo actualizado:

var bytes = Packages.org.apache.commons.codec.binary.Base64.decodeBase64( F1.getString().getBytes() );
var decString = new Packages.java.lang.String( bytes );

var encString = new Packages.java.lang.String( Packages.org.apache.commons.codec.binary.Base64.encodeBase64( decString.getBytes() ) );


Añadiendo filas dinámicamente

En los ejemplos encontrará una transformación llamada "JavaScript - create new rows.ktr", la cual crea nuevas filas basadas en el contenido de un campo.

En el ejemplo, esta es la entrada del paso Javascript:

Para cada uno de los valores en la columna "groupsField" queremos generar una nueva fila. Así es como se hacía en la versión anterior:
 

var groups = group.getString().split(",");

for (i=0;i<groups.length;i++)
{
  newRow = row.Clone();
  newRow.addValue( new Packages.be.ibridge.kettle.core.value.Value("subgroup", groups[i]).trim() );
  newRow.addValue( new Packages.be.ibridge.kettle.core.value.Value("ignore", "N").trim() );
  _step_.putRow(newRow);
}

var subgroup = "";
var ignore = "Y";

En la versión 3.0 se han separados los datos de los metadatos. También se agregaron algunos métodos al motor Javascript para mitigar el dolor en este aspecto:

if (groupsField!=null)
{
  var groups = groupsField.split(",");

  for (i=0;i<groups.length;i++)
  {
    newRow = createRowCopy(getOutputRowMeta().size());
    var rowIndex = getInputRowMeta().size();

    newRow[rowIndex++] = trim( groups[i] );
    newRow[rowIndex++] = "N";

    putRow(newRow);
  }
}

var subgroup = "";
var ignore = "Y";

Como puede verse, se agregaron algunos métodos:

método

explicación

getInputRowMeta()

Los metadatos de la fila de entrada, explicando el diseño de los datos de la fila y el objeto "row".

getOutputRowMeta()

Los metadatos de la fila de salida, determinada por los metadatos de entrada y los pasos extra especificados en este paso.

createRowCopy(size)

Crear una copia de los datos de la fila de entrada, pero redimensionar la fila resultado al largo especificado.

putRow(row)

Escribir una nueva fila a los pasos siguientes en la transformación. El tipo de datos pasado es Object[]. Los tipos de datos pasados DEBEN coincidir con los especificados en la sección "Campos" y por ende con la especificación en getOutputRowMeta(). No es legal especificar String para un campo y pasar un tipo de dato diferente.
Aquí se listan los tipos de datos permitidos:

  • String : java.lang.String
  • Number: java.lang.Double
  • Integer: java.lang.Long
  • Date: java.lang.Date
  • BigNumber: java.math.BigDecimal
  • Boolean: java.lang.Boolean
  • Binary: java.lang.byte[]

El resultado del script es en ambas versiones el siguiente:

Un simple filtro en el campo "ignore" genera el resultado deseado.
Creemos que la nueva API soportará mejor el examen del tiepo ya que ha sido escrita sin la utilización directa de código Java ó la API de Java.

  • No labels