Reconocimiento de patrones con expresiones regulares en Db2 11.1 para Linux, Unix y Windows

Nota del editor: Este artículo fue publicado originalmente en inglés. Con la aprobación del autor, el equipo de IDUG ha creado la traducción que a continuación se presenta.

Las expresiones regulares (regular expressions) son parte integral de las opciones de reconocimiento de patrones (pattern matching) en todas las variantes de software sofisticados, incluyendo comandos de sistemas operativos, editores de texto, lenguajes de programación e incluso manejadores de bases de datos. Desde la versión 11.1 de Db2 para Linux, Unix y Windows (y también Db2 para i 7.1 TR9), el uso de expresiones regulares ya está disponible como una función nativa de SQL (built-in SQL functions) y no dependen de wrappers de XQuery o rutinas externas (de Java o algún otro). Utilizando queries de ejemplo de Db2 11.1 Fix Pack 1 para Windows, este artículo muestra las nuevas funciones built-in de Db2 sobre expresiones regulares y también ofrece algunos puntos para considerar al adaptar sus cargas de trabajo (workloads) de SQL para poder tomar ventaja de estas funciones.

Todos los patrones de expresiones regulares en este artículo están ligados a diagramas SVG generados por Regexper, la cual es una utilería en línea creada por Jeff Avallone. Recomiendo ampliamente Regexper para documentar los patrones regex en sus proyectos.

 

Funciones para contar, reemplazar y encontrar patrones de texto

Las funciones REGEXP son funciones escalares (scalar functions) en el schema SYSIBM y toman como entrada un valor string, un patrón regex, y parámetros adicionales que varían de acuerdo a la función. Tienen un parecido cercano a las funciones de expresiones regulares que aparecieron por primera vez en Oracle 10g Release 1.

 

 

Hoja de resumen de expresiones regulares de IBM en Db2

La sintaxis de las expresiones regulares en Db2 se basa en las expresiones regulares extendidas de POSIX (POSIX Extended Regular Expressions), lo cual es un estándar implementado por la organización IEEE. Esta gramática que se propone es muy versátil y ofrece una amplia gama de posibilidades dentro del motor de SQL de Db2. El sitio de IBM Knowledge Center para Db2 11.1 tiene una lista detallada de los caracteres de control (control characters) que pueden ser utilizados para construir patrones de expresiones regulares. Los caracteres de control y su comportamiento pueden variar de un motor de expresiones regulares a otro, de manera que es más recomendable referirse a la página específica de Db2 al momento de trabajar con funciones REGEXP. En caso de que el URL de dicha página haya sido movido, la lista de caracteres de control también puede ser encontrada al ingresar la búsqueda “regular expression control characters”.

 

Conversión de múltiples sentencias LIKE a un REGEXP_LIKE

El predicado de LIKE en SQL ofrece una gramática de reconocimiento de patrones sencilla con solamente tres opciones: carácter literal, comodín de un solo carácter, y comodín de múltiples caracteres. De esta manera, no se requiere mucho para que una regla de filtrado y validación se haga compleja para describirse en un solo uso de LIKE. Por otro lado, las funciones REGEXP utilizan patrones que proveen mayores capacidades.

Ejemplo: Una compañía de ventas desea extraer (véase el siguiente query) y geo-localizar la lista de direcciones de sus clientes para identificar posibles ubicaciones de una nueva tienda. Para agilizar este proceso, el query que se utiliza va a ignorar algunos códigos postales que no se beneficiarían en este proceso de geo-localización. En lugar de utilizar una serie de LIKEs para describir todas las posibles maneras en las que un código postal se pudiera formatear, el query ejecuta REGEXP_LIKE una sola vez, evaluando los strings de las direcciones en un patrón regex.

 

WITH cust(street) AS (
-- Seis combinaciones de códigos no deseados (P.O. BOX), cada uno formateado de una manera diferente
    VALUES ('PO BOX 1'), ('PO  BOX 2'), ('P.O. BOX 3')
           , ('P O BOX  4'), ('P. O.BOX 5'), ('po box 6')
-- Y una dirección legítima que pertenece al result set
           ,('POBOXTON CT ROAD NO. 3')
)
SELECT street FROM cust
WHERE NOT REGEXP_LIKE( street, '^\s*P\.?\s*O\.?\s*BOX\b', 'i' );

 

Salida:

STREET
----------------------
POBOXTON CT ROAD NO. 3

 1 record(s) selected.

Query 1. La función REGEXP_LIKE evalúa la dirección utilizando un patrón no sensible a mayúsculas (case-insensitive) para identificar direcciones de códigos postales que deben ser filtrados y eliminados del result set. Esta bandera se encuentra como el tercer parámetro de este ejemplo, pero podría ser el cuarto parámetro en caso de que se utilice la tercera posición para especificar la posición de inicio.

 

Extracción y reemplazo de patrones de texto

Si su query sólo requiere validar una entrada de tipo string contra un patrón de búsqueda sencillo, podría ser suficiente al utilizar un par de predicados LIKE, funciones básicas de manejo de strings y tal vez la función TRANSLATE, sin embargo, generalmente este tipo de soluciones no podrá expandirse más allá de un resultado booleano. Si su query también necesita extraer porciones específicas del string de entrada que coinciden con un patrón de búsqueda, una función de expresiones regulares podría ser la única solución. REGEXP_EXTRACT, REGEXP_SUBSTR y REGEXP_REPLACE son tres funciones nativas que agilizan tareas complejas de reconocimiento de patrones que de otra manera sería demasiado laborioso o incluso imposible de lograr.

 

Ejemplo: La opción de soporte técnico de una aplicación móvil envía un correo email al teléfono del cliente para llenar una forma que será enviada al área de ayuda de la empresa. Esta aplicación pre-llena el cuerpo del mensaje con el string “Robot Food:” y el ID del cliente como referencia. Después de que un proceso batch dentro del servidor de la empresa inserta los datos en una tabla de Db2, los correos pueden ser utilizados en JOIN contra la tabla de clientes.

 

SELECT c.custid, c.fname, c.lname, c.emailaddr, m.msgbody
FROM hdesk.rcvemails AS m
LEFT OUTER JOIN core.customers AS c
ON c.custid = REGEXP_SUBSTR(
    m.msgbody, 'Robot Food:\s([0-9a-f]{10})', 1, 1, 'c', 1
)
WHERE m.msgstatus = 'RECEIVED';

 

Salida:

CUSTID     FNAME  LNAME EMAILADDR          MSGBODY
---------- ------ ----- ------------------ ---------------------------
3d5f2ac11e Jolene User  juser58@sample.com Hello, I have a question...

   1 record(s) selected.

Query 2. REGEXP_SUBSTR captura y regresa un string de 10 caracteres en hexadecimal a partir del cuerpo del mensaje. El parámetro número 6 limita la salida a la porción del patrón que aparece dentro del grupo de captura del paréntesis en lugar de mostrar las palabras “Robot Food:”, ya que esto último se encuentra fuera del grupo de captura.

 

Una cláusula OR para expresiones regulares

En lugar de utilizar la cláusula OR para encadenar múltiples funciones REGEXP_LIKE cuando exista más de un patrón de búsqueda, el operador de alternado (alternation operator), que es el símbolo ‘|’, puede combinar dichos patrones en un simple patrón regex. El motor de expresiones regulares va a trabajar en estas opciones de izquierda a derecha saliendo del alternado tan pronto como exista una coincidencia completa.

Además de que las funciones REGEXP pueden evaluar múltiples patrones en una sola llamada, también pueden trabajar sobre múltiples columnas de entrada si concatenan las columnas en el primer parámetro.

 

Ejemplo:

 

SELECT isocountry, postcode
, CASE WHEN REGEXP_LIKE( isocountry || postcode,
    '^US\d{5}(?:[- .]?\d{4})?\b|^CA[A-Z]\d[A-Z]\s\d[A-Z]\d\b'
) THEN 'VALIDATED' ELSE 'FAILED' END AS postcodevalid
FROM TABLE( VALUES
-- Estos tres registros van a coincidir con alguna de las opciones del alternado
   ('US','90210'), ('US','97201-3339'), ('CA','D2A 4F2')
-- Y estas tres no van a coincidir con nada
   ,('','12345'), ('US','1234o'), ('CA','1A3 C4G')
) AS unfilledorders( isocountry, postcode );

 

Salida:

ISOCOUNTRY POSTCODE   POSTCODEVALID
---------- ---------- -------------
US         90210      VALIDATED
US         97201-3339 VALIDATED
CA         D2A 4F2    VALIDATED
           12345      FAILED
US         1234o      FAILED
CA         1A3 C4G    FAILED

   6 record(s) selected.

Query 3. REGEXP_LIKE utiliza alternaciones para evaluar patrones específicos por país (en este caso, Canadá y Estados Unidos). Concatenar ISOCOUNTRY y POSTCODE en el primer argumento hace posible que los valores de las dos columnas sean evaluadas en la misma invocación de REGEXP_LIKE.

 

Cuidado con el martillo

Puede ser tentador adelantarse y adoptar de lleno esta mejora de Db2 como lo es el conjunto de funciones REGEXP. Sin embargo, el poder de las expresiones regulares viene con el precio de una sintaxis que podría ser compleja e incluso críptica para algunos, lo cual a su vez se podría convertir en un reto de diagnosticar en caso de problemas. Algunos queries que cumplen con su objetivo con funciones sencillas de TRANSLATE y REPLACE tal vez no requieran la inversión de tiempo en reescribir a esta nueva mejora.

 

Notas sobre el performance

De igual manera que algunos ajustes triviales en queries pueden tener un gran impacto en el access path seleccionado, elegir el operador incorrecto o cuantificador de una expresión regular sobre incluso una pequeña porción puede impactar negativamente los costos de CPU debido a un proceso conocido como backtracking (el cual puede ocurrir en el uso de los comodines *, *?, +, +?, {n,m}, y {n,m}?. Los costos adicionales de CPU sobre una expresión irregular ineficiente dentro de una llamada REGEXP pueden acumularse rápidamente cuando el query invoca dicha función sobre millones de registros como entrada. Afortunadamente, existe una amplia variedad de libros y artículos sobre el tema de construcción de expresiones regulares eficientes y la mayoría de la guía que ofrecen es aplicable a las funciones REGEXP de Db2. Escribir expresiones regulares eficientes en Db2 o algún otro motor será más sencillo al comprender temas como el funcionamiento del proceso de backtracking, lazy quantifiers, y los beneficios de possessive quantifiers.

 

La necesidad de soluciones temporales ha terminado

Cuando llega el momento de utilizar expresiones regulares en SQL de Db2, les recomiendo considerar funciones REGEXP sobre alguna otra alternativa. Por muchos años, las expresiones XQuery incrustadas (embedded) fueron una manera excelente de ubicar expresiones regulares en SQL, pero es tiempo de descontinuar su uso y reemplazarlos con llamadas a funciones REGEXP que son más directas e igualmente capaces. La misma actualización aplica para funciones definidas por usuario (UDF functions) y procedimientos almacenados (stored procedures) que fueron creados únicamente para procesamiento de expresiones regulares. En términos de utilización de recursos, el motor de Db2 puede invocar funciones nativas SYSIBM como REGEXP_LIKE y REGEXP_REPLACE mucho más eficientemente que al ejecutar un método de Java en un proceso JVM externo. Cuando sea aplicable, adoptar el uso de funciones REGEXP como reemplazo de soluciones anteriores no solamente va a hacer sus SQL más fácil de administrar, sino que también podría promover mejores access paths para el Optimizer.

 

Sobre Fred Sobotka

Fred Sobotka es un consultor de administración de datos en FRS Consulting. Ha ganado menciones y premios como presentador en las conferencias del IDUG, el título de IBM Gold Consultant, y pionero como IBM Champion que regularmente escribe y realiza presentaciones sobre temas complejos de Db2, desarrollo de aplicaciones de negocio y monitoreo de soluciones de alta disponibilidad. Fred comenzó su carrera en 1990 y ha trabajado con Db2 para Linux, Unix y Windows como desarrollador y DBA desde la versión DB2 Common Server V2.1 en 1996.

 

Recent Stories
IBM DB2 EN LA NUBE DE AMAZON AWS

JSON SQL APIs en Db2 para z/OS y servicios nativos REST

Un nuevo capítulo de IDUG en México