enero 06, 2013

SAP HANA Text Analysis


By Lucas Sparvieri

Con el lanzamiento de SPS05 SAP implemento una gran cantidad de cambios y nuevas funcionalidades, algunas muy esperadas por modeladores/desarrolladores, como la posibilidad de debuggear procedimientos (al fin!!). Pero desde mi punto de vista, una de las mejores nuevas funcionalidades es “Text Analysis”. El objetivo de esta nueva funcionalidad es extraer información relevante de textos. En otras palabras, las compañías ahora pueden procesar grandes volúmenes de fuentes de datos y extraer información relevante sin necesidad de tener que leer cada oración. Ahora, qué es información relevante? El proceso de extracción identifica los “quien”, “que”, “donde”, “cuando” y “cuanto” (entre muchas otras cosas) en datos no estructurados y de esta manera nos habilita a enriquecer los datos estructurados.
Si queremos entender de una manera sencilla cómo funciona, podemos referirnos al manual de desarrolladores de HANA:

“El análisis de texto proporciona un gran número de tipos de entidades posibles y reglas de análisis para muchas industrias en 20 idiomas. Sin embargo, usted no tiene que hacer frente a esta complejidad en el análisis de su conjunto de documentos. Los módulos de idiomas que se incluyen en el software contienen diccionarios y proporcionan un amplio conjunto de tipos de entidades predefinidas. El proceso de extracción puede extraer entidades que utilizan estas listas de entidades específicas. Durante la extracción se clasifica cada entidad extraída por tipo de entidad y se presentan estos metadatos en un formato normalizado”

Pero lo más impresionante de “Text Analysis” es lo fácil que es implementarlo. Los voy a guiar por los pasos que seguí para hacerlo funcionar:
Primero que nada, cree una tabla columnar con la siguiente estructura:


CREATE COLUMN TABLE "PRESS_RELEASES" (
       "File_Name" NVARCHAR(20),
       "File_Content" BLOB ST_MEMORY_LOB,
       PRIMARY KEY ("File_Name"));

En esta tabla voy a almacenar una serie de archivos PDF que contienen información de la industria de la aviación en Estados Unidos. Para eso cree un script en Python que guarda los archivos PDF en la columna de tipo BLOB de mi tabla (“File_Content”):

con = dbapi.connect(‘hanahost', 30015, 'SYSTEM', '********') #Open connection to SAP HANA
cur = con.cursor() #Open a cursor
file = open('doc.pdf', 'rb') #Open file in read-only and binary
content = file.read() #Save the content of the file in a variable
cur.execute("INSERT INTO PRESS_RELEASES VALUES(?,?)", ('doc.pdf',content)) #Save the content to the table
file.close() #Close the file
cur.close() #Close the cursor
con.close() #Close the connection
Ahora que tengo mi tabla cargada con datos no estructurados estoy listo para comenzar mi proceso de análisis de texto. Lo único que tengo hacer es correr la siguiente declaración:
Create FullText Index "PDF_FTI" On "PRESS_RELEASES"("File_Content")
TEXT ANALYSIS ON
CONFIGURATION 'EXTRACTION_CORE';


Lo que estoy haciendo acá es crear un “Full Text Index” llamado “PDF_FTI” (le pueden poner el nombre que quieran) en la columna BLOB “File_Content” de mi tabla “PRESS_RELEASES”. También estoy diciendo que quiero ejecutar el proceso de análisis de texto con la configuración llamada “EXTRACTION_CORE” (pueden referirse al manual de desarrolladores de HANA para entender cuáles son las diferentes configuraciones). Con la ejecución de este script se crea una nueva tabla columnar llamada $TA_PDF_FTI ($TA_<Nombre_del_Indice>) que contiene los resultados de mi proceso de análisis de texto. La estructura de esta tabla es la siguiente:


Columna
Key
Descripción
Tipo de Datos
File_Name
Si
Esta es la clave primaria de mi tabla. Si tu clave primaria está compuesta por más de una columna, esta tabla contendrá todas las columnas
El mismo que en la tabla original, en este caso: NVARCHAR(20)
RULE
Si
Almacena el paquete de reglas que produjo el “Token”. En mi caso: “Entity Extraction”
NVARCHAR(200)
COUNTER
Si
Cuenta todos los “Tokens” en el documento
BIGINT
TOKEN
No
El “Token” que fue extraído (los “quien”, “que”, “donde”, “cuando” y “cuanto”)
NVARCHAR(250)
LANGUAGE
No
Se puede especificar una columna de lenguaje en el momento de crear el “Full Text Index” o este se puede derivar del texto. En mi caso se derivó del texto y es Inglés.
NVARCHAR(2)
TYPE
No
El tipo de “Token”, si es “quien”, “que”, “donde”, “cuando” o “cuanto”
NVARCHAR(100)
NORMALIZED
No
Almacena una representación normalizada del “Token”. Esto es relevante, por ejemplo, para el alemán con diéresis.
NVARCHAR(250)
STEM
No
Almacena la información lingüística derivada, por ejemplo, el nominativo singular de los sustantivos, o el indicativo de los verbos.
NVARCHAR(300)
PARAGRAPH
No
El número de párrafo donde el “Token” está localizado en el texto
INTEGER
SENTENCE
No
El número de oración donde el “Token” está localizado en el texto
INTEGER
CREATED_AT
No
Fecha y Hora de creación
TIMESTAMP

Esta es una vista preliminar de mi tabla $TA:


Ahora pretendamos por un minuto que trabajamos en una aerolínea, por ejemplo Delta Air Lines, y nos gustaría saber si la compañía para la cual trabajamos fue mencionada en alguno de estos documentos. Fácilmente podemos encontrar la respuesta aplicando un filtro en la columna TYPE = ‘ORGANIZATION/COMMERCIAL’ y TOKEN = ‘Delta Air Lines’. Como pueden observar en la captura de abajo, Delta Air Lines fue mencionada dos veces en el documento bts201001.pdf (párrafos 9 y 151), dos veces en el documento bts201002.pdf (párrafos 9 y 136), etc.



















Soy muy escéptico por naturaleza, así que me gustaría averiguar si esto es realmente así. Por lo tanto, cree un script XS JavaScript muy simple para mostrar el contenido de uno de los archivos PDF (bts201002.pdf):
var conn = $.db.getConnection();
try {
var query = "Select \"File_Content\" From \"PRESS_RELEASES\" Where \"File_Name\" = 'bts201002.pdf'";
      var pstmt = conn.prepareStatement(query);
      var rs = pstmt.executeQuery();
      rs.next();
$.response.headers.set("Content-Disposition", "Content-Disposition: attachment; filename=bts201002.pdf");
      $.response.contentType = 'application/pdf';
      $.response.setBody(rs.getBlob(1));
      $.response.status = $.net.http.OK;
} catch (e) {
      $.response.setBody("Error while downloading : "+e);
      $.response.status = 500;
}
conn.close();
Como mi proceso de análisis de texto predijo, Delta Air Lines es mencionado dos veces en este documento en particular y está justo donde mi tabla $TA dijo que iba a estar:



Espero que les haya servido!

No hay comentarios:

Publicar un comentario