Friday, April 20, 2012

Limpiando data en SAP HANA con R

Del 10 al 11 de Abril, my equipo (Anne, Juergen y yo) realizamos un InnoJam en Boston. Fué realmente un evento excelente, pero la data proporcionada por la Ciudad de Boston no estaba exactamente en la mejor forma, asi que nos esforzamos bastante (con la ayuda de los Gurus de SAP) en limpiar la data.

Es cierto momento, me pidieron que utilizara mis habilidades en Expresiones Regulares (todo saben que estoy loco por el RegEx) para limpiar data que venia en un formato muy extraño dentro de un campo...algo como esto (No puedo publicar la data real por motivos obvios):

Type: [This is a test] Area: [My Area] Description: [This data is not right]

Lo que tenia que hacer basicamente, era tomar cada registro y generar una tabla con 3 campos que se veria mas o menos como esto...

TypeAreaDescription
This is a testMy AreaThis data is not right


Comencé a pensar en que lenguage sería el mejor para este trabajo...Pensé en ABAP, Python...y luego por supuesto en...R...así que escogí R.

Los problemas que saltaron al instante fueron simples, como sacar la información de  HANA y como enviarla de vuelta, además, aún cuando me considero un RegEx Hero, R no utiliza un esquema de RegEx muy estandard. Pensé en descargar la data de HANA como .CSV, limpiarla y luego subir el .CSV de vuelta a HANA...pero luego pensé que el trabajo extra no valía la pena...así que...my viejo y buen amigo RODBC entró en escena...aún cuando no esta soportado oficialmente por SAP, decidí que para este caso en particular, estaría perfecto...Podía leer la data de ida y vuelta y tenerla lista en HANA en muy poco tiempo.

Creemos una tabla y llamemosla BAD_DATA...y solo creemos 10 registros (Ya sé...Soy flojo)...


Así que aquí esta el script:

library("RODBC")
ch<-odbcConnect("HANA_SERVER",uid="P075400",pwd="***")
query<-("select case_description from P075400.BAD_DATA")
CRM_TAB<-sqlQuery(ch,query)
 
SR_Type<-c()
SR_Area<-c()
Description<-c()
 
for(i in 1:nrow(CRM_TAB)){
  mypattern = '\\[([^\\[]*)\\]'
  datalines = grep(mypattern,CRM_TAB$CASE_DESCRIPTION[i],value=T)
  getexpr = function(s,g)substring(s,g,g+attr(g,'match.length')-1)
  g_list = gregexpr(mypattern,datalines)
  matches = mapply(getexpr,datalines,g_list)
  result = gsub(mypattern,'\\1',matches)
  var<-0
  i<-0
  for(i in 1:length(result)){
    var<-var+1 
    if(var==4){
      break
    } 
    if(var==1){
      SR_Type<-append(SR_Type,result[i])
    }
    if(var==2){
      SR_Area<-append(SR_Area,result[i])
    }
    if(var==3){   
      Description<-append(Description,result[i])
    }
  }
  if(length(SR_Type)>length(Description)){
    Description<-append(Description,NA)
  }
  if(length(SR_Type)>length(SR_Area)){
    SR_Area<-append(SR_Area,NA)
  } 
}
 
GOOD_DATA<-data.frame(SR_Type,SR_Area,Description,stringsAsFactors=FALSE)
sqlDrop(ch,"GOOD_DATA",errors=FALSE)
sqlSave(ch,GOOD_DATA,rownames="id")
odbcClose(ch)


Así que basicamente, lo que hacemos es tomar la información que esta dentro de los corchetes [ ], luego pasarla a vectores para finalmente crear un Data.Frame y enviarlo de vuelta a HANA. Si se preguntan porque estoy comparando la longitud de los vectores para agregar valores NA, es muy simple...podemos tener algo como esto...

Type: [This is a test] Area: [My Area] Description: [This data is not right |

El último corchete...no es un cochete! Es un pipe (O como se llame en Español), así que el RegEx va a fallar y esto va a provocar que el vector este vacio y esto se puede poner feo...si esto sucedes, podemos poner un valor NA y al menos tener un valor...

Así que...cuando corremos nuestro programa...una nueva tabla llamada GOOD_DATA va a ser creada con toda la data limpia y lista para usar.


Elegante, no? -;)

Nos vemos en mi próximo blog! -:)

No comments: