sábado, 31 de agosto de 2013

Soluciones SAS Big Data

Cada día toman más relevancia los sistemas “Big Data” y la gestión de los mismos. A continuación recopilo algunos links interesantes sobre las soluciones que SAS ofrece en este tipo de entornos.



jueves, 29 de agosto de 2013

Tratamiento de fechas en SAS (III). Diferencias entre fechas.

Es habitual la necesidad de obtener diferencias entre fechas para realizar validaciones o ejecuciones condicionadas en los procesos. A continuación un sencillo ejemplo que obtiene diferencias entre fechas en diferentes unidades (días, meses, años) y realiza desplazamientos partiendo de una fecha determinada.
Así mismo, un paso data de ejemplo que obtiene todos los días de un mes determinado.

data funciones_f;
length fecha1_num fecha2_num 8.;
fecha1_num = 20121001;
fecha2_num = 20131001;
fecha_h_date = today();
run;




data funciones_f_01(drop = fecha_h_date_suma_1dia fecha_h_date_suma_1mes fecha_h_date_suma_1anyo );
set funciones_f;
/* Transformamos las variables numérica con contenido fecha yyyymmdd a variable tipo fecha */
fecha1_date = mdy((mod((int(fecha1_num/100)),100)),(mod(fecha1_num,100)),(int(fecha1_num/10000)));
fecha2_date = mdy((mod((int(fecha2_num/100)),100)),(mod(fecha2_num,100)),(int(fecha2_num/10000)));
/* Partiendo de una variable tipo fecha que contiene la fecha del día, la convertimos en un
numérico con formato yyyymmdd */
fecha_h_num = input(put(fecha_h_date,yymmddn8.),8.);
/* Obtenemos diferencias entre fechas en días, meses y años */
dif_dias=intck('day',fecha1_date,fecha2_date);
dif_dias_lab = intck('weekday',fecha1_date,fecha2_date); /* Diferencia de días, en días laborables */
dif_meses=intck('month',fecha1_date,fecha2_date);
dif_años=intck('year',fecha1_date,fecha2_date);
/* Desplazamos la fecha del día en una unidad: días, meses o años */
fecha_h_date_suma_1dia = intnx('day',fecha_h_date,1);
fecha_h_num_suma_1dia = input(put(fecha_h_date_suma_1dia ,yymmddn8.),8.);
fecha_h_date_suma_1mes = intnx('month',fecha_h_date,1);
fecha_h_num_suma_1mes = input(put(fecha_h_date_suma_1mes ,yymmddn8.),8.);
fecha_h_date_suma_1anyo = intnx('year',fecha_h_date,1);
fecha_h_num_suma_1anyo = input(put(fecha_h_date_suma_1anyo ,yymmddn8.),8.);
/* Obtener el día, mes y año de la fecha del día */
dia_h = day(fecha_h_date);
mes_h = month(fecha_h_date);
anyo_h = year(fecha_h_date);
/* Partiendo de la fecha del día en formato fecha-hora, dividir en fecha y hora */
datetime_h = datetime();
date_h = datepart(datetime_h);
time_h = timepart(datetime_h);
format date_h date9. datetime_h datetime. time_h time.;
run;


/* Obtener todos los días de un mes */

%let mes = 201309;

data funciones_f_m (keep = dia_mes) ;
dia_ini = &mes.01;
i = 0;
val_mes = 1;
dia_mes_ini = mdy((mod((int(dia_ini/100)),100)),(mod(dia_ini,100)),(int(dia_ini/10000)));
do while (val_mes = 1);
    dia_mes_aux = intnx('day',dia_mes_ini,i);
    i = i + 1;
    dia_mes = input(put(dia_mes_aux ,yymmddn8.),8.);
    if round(dia_mes/100) = &mes. then do;
        val_mes = 1;
        output;
    end;
    else do;
        val_mes = 0;
    end;   
end;
run;

Funciones numéricas básicas

A continuación un sencillo ejemplo, que contiene un  resumen de las funciones numéricas SAS de más uso para realizar las operaciones básicas con números (agregados, medias, valor absoluto, redondeos, etc..).

data funciones_n;
importe1 = 5; importe2 = 4; importe3 = 4; s_importe = -1;output;
importe1 = 6; importe2 = 5; importe3 = 5; s_importe = 3; output;
importe1 = 10; importe2 = 7; importe3 = 6; s_importe = -2; output;
importe1 = 8; importe2 = 4; importe3 = .; s_importe = -1; output;
importe1 = .; importe2 = 0; importe3 = 5; s_importe = 1; output;
run;


data funciones_n_1;
set funciones_n;
c_importe_min = min(importe1, importe2, importe3); /* Valor mínimo */
c_importe_max = max(importe1, importe2, importe3); /* Valor máximo */
c_importe_total = sum(importe1, importe2, importe3); /* Sumatorio importes */
c_importe_total = sum(of importe1-importe3); /* Otra forma de indicar que sume de importe1 a 3 */
c_importe_total = sum(of imp:); /* Suma todos los campos que empiecen por imp: */
c_importe_med_s = (importe1 + importe2 + importe3)/3; /* El resultado es diferente al de
                                        la funcion mean en caso de haber nulos */
c_importe_medio = mean(of imp:); /* Valor medio */
c_importe_medio_r = round(c_importe_medio, .01); /* Valor importe medio redondeado a 2 decimales */
c_importe_medio_f = floor(c_importe_medio); /* Redondea a la baja */
c_importe_medio_c = ceil(c_importe_medio); /* Redondea al valor superior */
c_signo_importe = sign(s_importe); /* Devuelve el signo del importe -1 o 1 */
c_abs_importe = abs(s_importe);  /* Devuelve el valor absoluto */
c_des_estandar = std(of imp:); /* Devuelve la desviación estandar */
c_varianza = var(of imp:); /* Devuelve la varianza - medida de dispersión */
run;

Funciones cadenas de caracteres SAS (II). Búsqueda de caracteres en cadenas

Es habitual en el tratamiento de cadenas la búsqueda de caraceteres o patrones determinados en las cadenas. A continuación un sencillo ejemplo en el que sobre una cadena de texto se realizan determinadas búsquedas. Se muestran también funciones que reemplazan un caracter o patrón por otro.

data funciones_t;
length campo1 $50.;
campo1 = 'Cadena de texto de ejemplo';
run;

data funciones_t_1;
set funciones_t;
campo2 = index(campo1, 'e'); /* Busca el carácter indicado y devuelve la posición que ocupa */
campo3 = indexw(campo1, 'ejemplo'); /* Busca una cadena de caracteres y devuelve la posición */
campo4 = count(campo1, 'e'); /* Devuelve el número de veces que el caracter indicado
                                aparece en la cadena */
campo5 = anyalpha(campo1); /* Busca el primer alfanumérico y devuelve su posición */
campo6 = anydigit(campo1); /* Busca el primer dígito y devuelve su posición */
campo7 = substr(campo1, index(campo1, 't'), 5); /* Busca el caracter indicado y partiendo
                                    de él obtiene una cadena de 5 caracteres */
campo8 = scan(campo1, 1, ' '); /* Obtiene todos los caracteres que hay desde la izquierda
                            hasta la primera ocurrencia del caracter indicado */
campo9 = scan(campo1, 2, ' ');
campo10 = translate(campo1, 'i', 'e'); /* Busca el segundo caracter y lo reemplaza por el primero */
campo11 = tranwrd(campo1, 'ejemplo', 'example'); /* Busca la cadena indicada en el
                        el primer argumento y la sustituye por la segunda */
run;


sábado, 10 de agosto de 2013

Creación de índices en tablas SAS


En el siguiente ejemplo, mostramos las sentencias necesarias para crear y usar un índice en SAS. Los índices mejoran notablemente el rendimiento en las consultas que utilizan los campos claves del índice. Recordar que, así mismo,  las actualizaciones de datos en la tabla, se ven ralentizadas por la existencia del índice.




/* Creamos la data de ejemplo */

 

data prueba(drop = i);
do i = 1 to 1000000;
campo1='abc';
campo2=i;
campo3 = round(ranuni(100), 0.01);
output;
end;
run;


/* Con la siguiente sentencia obtenemos información sobre la creación y uso del índice */

options msglevel=i;
 


/* Creamos un índice por el campo campo3 */

proc sql;
create index campo3 on prueba (campo3);
quit;

 

/* Se puede forzar en un paso data el uso del índice */

 

data prueba1;
set prueba (idxwhere=yes); /* forzamos el uso del índice */
where campo3 = 0.5;
run;

 
/* Borrado del índice */

 
proc sql;
drop index campo3 from prueba;
quit;

 

 
 
 

miércoles, 7 de agosto de 2013

Selección de una herramienta ETL

Al abordar un proyecto de Business Intelligence es importante la correcta valoración de la herramienta ETL que vamos a utilizar. SAS proporciona interesantes herramientas ETL como puede ser SAS/Data Integration Studio, pero vamos a realizar un breve análisis sobre los aspectos a valorar en la selección de este tipo de herramientas.
La herramienta ETL será la base para diseñar e implementar los procesos de abastecimiento del Datamart , Datawarehouse o estructura de almacenamiento en base a la cual posteriormente explotaremos los datos. Se trata de una pieza fundamental para el diseño, construcción y posterior evolución de nuestro sistema B.I. Analizaremos únicamente cuestiones técnicas, sin entrar a los aspectos económicos o de otra índole (licencias, acuerdos, soporte técnico, evoluciones de la herramienta, etc..). Señalar que los procesos de ETL, van muy ligados a los procesos de data profiling y de calidad de datos, que aquí no vamos a considerar.
Brevemente y como inicio recordamos que ETL son las siglas en inglés de Extraer, Transformar y Cargar (Extract, Transform and Load). En base a estos tres pasos básicos en el diseño de los procesos, vamos a proponer aspectos a considerar en la selección de una herramienta de este tipo. Posteriormente veremos las cuestiones relativas a su explotación.

 

Diseño de los procesos


Extracción



El primer paso es la extracción de los datos desde los sistemas de origen que pueden ser múltiples y con múltiples formatos. Es importante en esta fase una correcta validación de los datos de origen y una homogeneización de los mismos. Es importante considerar el volumen que vamos a tratar y realizar este paso sin causar impacto en los sistemas de origen (procesos batch). Vamos a considerar en este paso tanto la extracción, como la validación de los datos leídos.
En lo que respecta a esta etapa, una herramienta ETL es conveniente que cumpla los siguientes aspectos:
  • Conectividad: capacidad para mapear múltiples orígenes como diferentes SGDB, diferentes tipos de modelos (relacionales, no relacionales), tipos de ficheros y formatos (host, XML, Excel, etc..), tipos de sistemas origen (ERP’s, SCM, sistemas propios), formatos de mensajes estándar (ej. SWIFT), colas de mensajería, downloads, etc..
  • Facilidades para el análisis y mapeos de los formatos o modelos de datos origen.
  • Admitir múltiples frecuencias de actualización. Las múltiples fuentes de datos de origen tienen diferentes ciclos de recepción y de actualización. La frecuencia de recepción puede cambiar de una a otra, así como las necesidades de actualización. Importante, la capacidad de incluir puntos de control entre las fuentes en los que garanticemos su sincronización.
  • Capacidad de incorporar datos de formatos no estructurados (documentos ofimáticos, e-mails, websites, logs,  etc). El campo de los datos no estructurados es inmenso y en plena evolución, es complicado de evaluar.
  • Gestión de las valiaciones técnicas: nulos, valores únicos, integridad referencial, campos obligatorios, rangos de valores, etc…y de las validaciones de negocio: reglas para comprobar las consistencia de los datos basándonos en los requerimientos de negocio.
  • Gestión de errores. Detección de los mismos y aplicación de acciones.
  • En caso de tratarse de una herramienta que desde la metadata genera código, ver la posibilidad de realizar ingeniería inversa: del código a la metadata.


Transformación



La fase de transformación consiste en realizar pasos de transformación o creación de nuevos datos en base a los recibidos y aplicando las reglas de negocio particulares de cada sistema. Existen pasos comunes a casi todos los procesos de transformación, tales como: selección de columnas a tratar, transformación de codificaciones (columnas codificadas de forma diferente en sistema origen respecto al sistema destino), calcular nuevas columnas en base a las columnas recibidas, realizar agregaciones, cruces de datos entre diferentes fuentes, etc…
  • Componentes predefinidos que incorpora la herramienta para realizar diferentes tipos de transformaciones muy extendidas (filtrados, cruces, mapeos, etc..)
  • Soporte para test y debugging que facilite el seguimiento de las transformaciones del proceso.
  • Posibilidades de incorporar código externo (no generado por la herramienta).
  • Posibilidad de crear procedimientos propios y utilizarlos otros procesos (reutilización de código/procesos).
  • Posibilidades para optimizar los proceso de tratamientos de datos voluminosos o costosos ante problemas de rendimiento.
  • Trazabilidad del dato. Disponer de un rastro de todas las transformaciones de un valor a lo largo del proceso. En el caso ideal, metadata consultable por el usuario, para que pueda realizar seguimiento en caso de detectar datos correctamente cargados, pero incoherentes de cara a negocio.

Carga


Esta última etapa, consiste en el volcado de los datos ya leídos, validados y tratados en la estructura analítica para su posterior explotación.
  • Considerar diferentes tipos de tablas destino (en general objetos BBDD de almacenamiento).
  • Considerar diferentes tipos de carga: borrado y volcado completo, carga incremental, etc…
  • Creación de procesos de agregación. Considerar diferentes niveles de agregación y organización de los datos (cubos, BBDD multidimensional).
  • Volcados de datos que consideren  diferentes niveles de agregación y organización de los datos en las tablas destino (cubos, BBDD multidimensional).
  • En esta etapa es igualmente importante el rendimiento: Procesamiento de volcados en paralelo para optimizar tiempos de volcado.

Una vez analizados los aspectos relevantes en el diseño de los procesos, revisamos los aspectos a considerar en la explotación y mantenimiento y evolución de la herramienta.

Explotación y mantenimiento de la herramienta


  • Adaptación a las diferentes plataformas hardware y sistemas operativos existentes.
  • Facilidad de uso. Interfaz intuitiva. Sencilla representación grafica de los objetos del repositorio, modelos de datos y flujos de datos.
  • Posibilidad de realizar análisis de impacto. Ver las implicaciones que un cambio en el modelo de datos o en los procesos tiene en todo el proyecto.
  • Versionado de código. Control de cambios. Gestión del trabajo en grupo.
  • Posibilidades de documentación.
  • Rapidez de consulta y actualización de la metadata o posibilidades de optimizarla (índices).
  • Posibilidades para planificar jobs: planificaciones batch, ejecuciones basadas en eventos, disparadores, etc…
  • Gestión de la cadena de ejecución. Dependencias entre procesos. Rearranque de jobs.
  • Sistema de logs. Logs detallados de ejecución/errores y recolección de estadísticas de ejecución (logs de resumen de cargas: fecha carga, registros cargados, registros erróneos, etc..).
  • Herramientas para monitorizar procesos y evaluar el rendimiento de los jobs (resource analyzer).
  • Compatibilidad con CWM (Comun Warehouse Metamodel). Capacidad para exportar o importa metadatos a otras herramientas ETL.
  • Actualización continua: El aumento de los volúmenes de datos pueden hacer que los lotes que se procesaban a diario pasen a procesarse en micro-lotes (varios al día) o incluso a la integración con colas de mensajes o a la captura de datos modificados (CDC: Change Data Capture) en tiempo real para una transformación y actualización continua.
  • Integración con el resto de componentes de la plataforma analítica, con el resto de los componentes de la plataforma de integración de datos (data profiling, calidad de datos) y con los componentes más orientados a explotación, análisis y presentación (capa reporting, dashboards, data mining, etc..).
  • Capacidad de adaptación a estándares que permitan el fácil intercambio de datos (ejemplo SOA).
  • Capacidad de interoperabilidad con otras herramientas (ej. Vía API).
  • Cuestiones de seguridad propias de cualquier herramienta.
Como es lógico, este breve compendio, trata aspectos generales que posteriormente deberán ser complementados con la problemática particular de cada sistema, infraestructura tecnológica, requerimientos de negocio y necesidades de información. En particular, en los proyectos 'Big Data', sería necesario añadir consideraciones adicionales de almacenamiento, volumen y rendimiento.

jueves, 1 de agosto de 2013

Diccionario de SAS: tablas dictionary.tables y dictionary.columns

En ocasiones resulta útil acudir al diccionario de SAS para obtener información
de la estructura de las tablas con las que trabajamos.
A continuación un sencillo ejemplo que accede a las tablas dictionary.tables
y dictionary.columns para obtener todas las tablas y sus columnas contenidas
en una determinada librería

/* Creamos tablas de trabajo: prueba1 y prueba2 */

data prueba1;
var1='a';var2 = 5;
run;

data prueba2;
varc = 'c';varn = 8;
run;



%macro obtener_campos(libreria);

%put Obtenemos tablas y campos de la librería &libreria;

/* Obtenemos todas las tablas contenidas en la librería, las recorremos
con una estructura de control iterativa obteniendo para cada tablas
todas sus columnas */

PROC SQL;
create table tablas as (SELECT memname
FROM dictionary.tables WHERE libname= upcase("&libreria") );
quit;

%let dsid = %sysfunc (open(tablas));    
%let nobs = %sysfunc (attrn(&dsid, NOBS));
%if &nobs > 0 %then %do;
%do i = 1 %to &nobs;     
%let rc = %sysfunc (fetch(&dsid));                                                                                                                                                                                                                                          
%let tabla = %sysfunc (getvarc(&dsid,1));  
%put Obtenemos campos tabla = &tabla;

/* Obtenemos todas las columnas y el tipo de cada una para una tabla determinada */

PROC SQL;
create table columnas as (SELECT name, type
  FROM dictionary.columns WHERE libname= "WORK" AND memtype = 'DATA' and                    memname="&tabla");
quit;

%let dsidc = %sysfunc (open(columnas));    
%let nobsc = %sysfunc (attrn(&dsidc, NOBS));
%if &nobsc > 0 %then %do;
%do j = 1 %to &nobsc;     
%let rc = %sysfunc (fetch(&dsidc));                                                                                                                                                                                                                               
%let columna = %sysfunc (getvarc(&dsidc,1));
%let tipo = %sysfunc (getvarc(&dsidc,2));
%put Nombre columna = &columna y tipo = &tipo;
%end;
%end;
%let rc = %sysfunc (close(&dsidc));

%end;
%end;
%let rc = %sysfunc (close(&dsid));

%mend;

%obtener_campos(WORK);