Un único paquete DTS capaz de importar datos desde SQL Server y Oracle

Si alguna vez tu jefe te pide que escribas un único DTS que sea capaz de atacar tanto a SQL Server como a Oracle… ¡trata de disuadirle! Si no lo consigues y tienes que emprender la labor, tal vez este post te ayude.

El otro día me pidieron precisamente esta misión imposible: modificar un DTS para Integration Services escrito para importar datos desde una base de datos SQL Server, para que pudiese importar datos desde una Oracle con un mismo esquema relacional. Hoy he conseguido que funcione en ambas bases de datos sin más cambios que la cadena de conexión… así que allá va la receta que tal vez no te asegure el éxito, pero que estoy seguro de que te facilitará las cosas.

  • El primer consejo es sencillo: Utiliza DataSources en lugar de usar directamente orígenes OleDB. En un DataSource puedes cambiar mil veces la cadena de conexión, que no afectará a tu ETL. En un origen OleDb "normal" SSIS no deja cambiar el cliente  sin tener que eliminar el origen completo y crear uno nuevo. Si no puedes usar un DataSource, hay un pequeño truco que te puede ayudar: modificar directamente la propiedad "ConnectionString" desde el diálogo de propiedades del control (sin hacer doble click en el nodo). Los DataSources no existían en los DTS de SQL Server 2000… son una nueva abstracción de SQL Server 2005 que te permiten definir una conexión a la que luego poder referirte desde tantos DTS como quieras. Alterando el DataSource, ¡estás alterando todos los orígenes de datos que hacen referencia al mismo!
  • Nunca referencies directamente una tabla. Utiliza siempre sentencias SQL. Las referencias a tablas están bien para hacer pruebas y prototipar tu ETL, pero el ETL definitivo jamás debe leer directamente una tabla. El primer motivo ya lo he expuesto alguna que otra vez… seguro que no usas todos los campos de la tabla… ¿entonces para qué te los traes a SSIS? No desperdicies buffers cargando datos que no vas a usar. Además, si vas a usar Oracle y SQL Server, ten en cuenta que los nombres de las tablas se especifican de forma diferente en ambas bases de datos. Puedes llevarte la desagradable sorpresa de tener que cambiar todas las referencias a tablas del formato [schema].[tabla] a "TABLESPACE"."TABLA".
  • En las fuentes de datos de las que vayas a leer de tablas Oracle, y pienses traerte campos de texto, pon a "true" la propiedad "AlwaysUseDefaultCodePage" y establece a mano la tabla de códigos usada por Oracle. Los proveedores OleDB de Oracle no proporcionan esta información a Integration Services, y con esta operación evitarás molestos warnings (que por otra parte, es seguro ignorar si se ha establecido la tabla de códigos por defecto en la fuente de datos).
  • No hagas cálculos en las SQL. En lugar de usar funciones SQL, utiliza la transformación "Derived Column" de SSIS. Además de evitar líos con funciones incompatibles entre los distintos tipos de datos, evitarás que errores en las funciones queden enmascarados (prueba a poner en una SQL una función que divida un número por cero, y observarás que el error queda totalmente oculto).
  • Si tienes que atacar a Oracle 8, recuerda que no soporta la sintaxis estándar ANSI de la Left Outer Join. Si tienes costumbre de usar este tipo de Join para limpiar aquellos datos en los que se ha roto la integridad referencial, usa en su lugar la transformación "Lookup" de SSIS. Es menos eficiente, pero es el precio que hay que pagar por al compatibilidad.
  • En tiempo de diseño, conecta el DataSource a una base de datos SQL Server en lugar de Oracle. SSIS necesita acudir a la fuente de datos para cargar los metadatos externos. Mi experiencia es que esto va mejor con SQL Server, y que te evitas malas pasadas del generador de consultas (que te genere, por ejemplo, nombres de tabla totalmente calificados con el formato de Oracle).
  • Si hay ligeras variaciones en los tipos de datos, usa la transformación Convert de SSIS justo inmediatamente después de leer los datos de la base de datos. Si haces esto, pon a "false" la propiedad "ValidateExternalMetadata". De esta forma, SSIS no validará los metadatos que cargó en tiempo de diseño contra los metadatos de la base de datos que actualmente tiene conectada. O sea, si en SQL Server se están usando tipos NVARCHAR y en Oracle VARCHAR, se podrá cambiar de una base de datos a otra sin que SSIS se queje por el cambio. La conversión debe realizarse justo después de la carga de los datos, y a partir del nodo conversor, el resto de nodos deben validar los metadatos externos. Los metadatos se usan, entre otras cosas, para que SSIS reserve espacio a sus buffers, así que es imprescindible que los metadatos establecidos en el flujo de datos coincidan con la realidad ANTES DE QUE SE REALICE LA PRIMERA TRANSFORMACIÓN ASÍNCRONA (Sort, Merge, Merge Join, Multicast… etc). Recuerda que SSIS genera un buffer con cada transformación asíncrona, así que si en ese preciso instante, los metadatos no están establecidos correctamente, Integration Services fallará.
  • Esta última técnica que he descrito no funciona con las transformaciones "Lookup". Vamos, que en mi caso al menos, por más que establezca a "false" la propiedad "ValidateExternalMetadata", sigue fallando la Lookup al cambiar el origen de datos (SSIS 2005 con SP1). No problemo: se puede sustituir la Lookup por la lectura desde un origen OleDB junto con la transformación Merge.

Espero que con estos consejos y un poco de esfuerzo, seas capaz de sorprender a tu jefe.

¡Felices transformaciones!

Patrones de diseño multidimensional

El primer diseño de un datamart siempre es duro. Uno no tiene muy claro por qué tipo de esquema relacional se debe decantar, qué elementos deben constituir las dimensiones, cuales son los hechos objetivo de análisis… da igual que partamos de un sistema OLTP ya existente, o que estemos partiendo de la nada: son decisiones que todo analista tiene que tomar, y son decisiones que ahora mismo las están tomando miles de cerebros mientras yo escribo estas líneas. Vaya… problemas similares… decisiones que se toman una y otra vez… ¿eso suena a patrones, no?

No hay muchos patrones relacionados con el mundo del "business intelligence", pero por suerte, esta situación empieza a mejorar a rápidamente.

Los Dimensional Design Patterns (DDP)

Este es un conjunto de patrones que nos ayuda a identificar las dimensiones de un cubo OLAP, así como los atributos asociados a cada miembro de la dimensión. Son muy útiles, sobre todo cuando empezamos. Para el que ya tenga algún diseño a su espalda, estoy seguro de que le servirán para emparejar todas las dimensiones que haya diseñado con un patrón existente. Éstos patrones están aún en pleno desarrollo, pero sus creadores ya han publicado un artículo en la revista de la ACM en la que exponen su investigación. A mi personalmente me han parecido muy útiles. Los podéis leer en el siguiente artículo:  

 

Dimensional modeling: identifying, classifying & applying patterns

Full text

pdf formatPdf (289 KB)

Source

Data Warehousing and OLAP archive
Proceedings of the 8th ACM international workshop on Data warehousing and OLAP table of contents

Bremen, Germany
SESSION: Data warehouse models table of contents
Pages: 29 – 38  
Year of Publication: 2005
ISBN:1-59593-162-7

Authors

Mary Elizabeth Jones  Drexel University, Philadelphia, PA
Il-Yeol Song  Drexel University, Philadelphia, PA

 

La literatura de "Project REAL" (Microsoft)

Otra joya de Internet es el llamado "Project REAL". No son patrones en sí mismos, o al menos no están escritos como tales… pero sí que son documentos que explican decisiones tomadas y lecciones aprendidas durante un proyecto real, realizado por Microsoft para Barnes & Noble. Podéis encontrar toda esta información en: http://www.microsoft.com/sql/solutions/bi/projectreal.mspx.

Ya se que no es mucho pero…

El mundo está esperando que compartas tus patrones de Business Intelligence. Yo sólo conozco estas dos direcciones de interés, pero… ¿por qué no escribes un comentario, o me dejas un mensaje con los enlaces a tus patrones favoritos? ¡Prometo recopilarlos, revisarlos y subirlos a geeks!

¡Felices búsquedas!

¿Estrella o copo de nieve?

A todos nos ha pasado: empezamos un nuevo proyecto y nos enfrentamos al diseño de un nuevo datamart… es importante hacerlo bien, porque será la base para nuestros cubos OLAP. ¿Debemos diseñar el almacenamiento relacional subyacente en estrella, o en copo de nieve? Lo cierto es que sobre este tema han corrido ríos de tinta, y sin embargo parece que aún hay discusiones. ¿Cual es la elección correcta?

Una variable multidimensional, dos bases de datos

Lo primero para decantarse por uno u otro diseño es tener bien claro cómo se almacena una variable multidimensional. La mejor forma de comprender la naturaleza de una variable multidimensional es compararlo con un sistema cartesiano.

  • Las dimensiones, son los ejes del sistema.
  • Los hechos, son los "puntos" que vamos a ubicar en esos ejes.
  • Estos "puntos" deben colocarse en coordenadas enteras dentro de los ejes cartesianos: jamás en coordenadas que se representen por medio de fracciones. Como muchos de los "puntos" que queremos representar contienen "fracciones" en sus coordenadas, tenemos que agregarlos para llegar a representarlos en el sistema. Tanto estos "puntos", como los distintos valores que puede tomar una coordenada, se cargan de una base de datos relacional (el datamart).
  • Las dimensiones de una variable multidimensional tienen "niveles". Para cada nivel sucesivo, las coordenadas cartesianas de esa dimensión se "espacian", de forma que los puntos a representar deben establecerse en un sistema "menos preciso". Por lo tanto, es necesario volver a agregarlos.

Por lo tanto, el espacio ocupado por un volumen multidimensional viene condicionado por:

  • Los hechos (puntos) que queremos representar.
  • El número de dimensiones de ese "volumen cartesiano" (los más puristas me diréis que no es un "volumen", sino un sistema… pero bueno, si nos ponemos puristas tampoco hablaríamos de cubos, sino de hipercubos, ¿no?)
  • El número de distintos valores que puede tomar cada dimensión (cómo de "espaciada" esté la componente cartesiana que sitúa un punto en esa dimensión).
  • El número de niveles de una dimensión, considerando a su vez la colección de posibles valores de ese nuevo nivel.

Los metadatos que dan la forma al cubo, y los agregados que constituyen el conjunto de puntos representado sobre el sistema cartesiano se almacenan en un volumen de datos multidimensional (por ejemplo, lo que sería la base de datos de Analysis Services). Los hechos que queremos agregar en el espacio multidimensional y los valores que pueden adoptar cada una de las coordenadas del sistema cartesiano, se cargan de una base de datos relacional (el datamart, que iría soportado, por ejemplo, sobre SQL Server).

Para aquellos a los que os queden dudas acerca de cómo se representa una variable multidimensional, os recuerdo que leáis el artículo de mi amigo y excelente divulgador Manuel de la Herran "Cómo diseñar grandes variables en bases de datos multidimensionales" (http://www.redcientifica.com/doc/doc200104190004.html).

Bien, ahora ya podemos empezar a entender las razones para adaptar un diseño en estrella o en copo de nieve.

La belleza de lo simple

Todo diseñador novel que se precie, y que venga del mundo relacional, tendrá una tendencia "natural" a normalizar… y aunque nos parezca mentira, lo más normal es al estudiar lo que será una dimensión, nos salga normalizada. Generalmente, por cada nivel de una dimensión, nos saldrá una tabla en el modelo relacional. Sin embargo, aunque el diseño más fácil de entender para un desarrollador sea el de un conjunto de dimensiones normalizadas (copo de nieve), fijaros en cómo trabaja un analista de negocio sobre Excel… EXACTO: no normaliza en exceso. Si está separando hombres de mujeres en una lista, escribe "Hombre" y "Mujer" al lado de cada nombre: no escribe un 1 o un 2, y pone una nota a pie de página que dice "Leyenda: ver tabla de codificación del género". Los modelos normalizados son fáciles de entender para las máquinas, pero difíciles de leer para el hombre. He aquí la primera razón para no normalizar las dimensiones: una estrella es mucho más fácil de comprender y manejar que un copo de nieve.

Unos cuantos tópicos sobre las estrellas y los copos de nieve

En general, si uno busca por Internet, las razones que esgrimen los defensores de cada uno de los diseños, son las siguientes:

  • El modelo en copo de nieve requiere menos espacio de almacenamiento. Esto es falso casi en todos los casos. Si nos fijamos en el conjunto de agregados de una variable multidimensional (el volumen del que os he hablado al comienzo del post) veremos que el número de valores disitintos que adopta una dimensión, así como el número de niveles de la misma, ES INDEPENDIENTE del DISEÑO relacional subyacente. Tenemos el mismo número de niveles y tenemos el mismo número de valores posibles para las coordenadas en esa dimensión, con lo que el espacio del volumen multidimensional ES EL MISMO. Bien, ¿entonces por qué he insinuado que esta frase es correcta para algunos casos? Aunque el volumen multidimensional de espacio que consumirá esa dimensión es el mismo, no es el mismo el espacio RELACIONAL que consumirá la dimensión en el datamart desde la que se carga. Si tenemos dimensiones EXTREMADAMENTE GRANDES, y en la que muchos atributos de la dimensión se encuentran repetidos o son nulos para determinados tipos de valores, al normalizar esta dimensión, ganaremos espacio en el datamart (recordemos que el datamart es una proyección bidimensional del espacio multidimensional, no el espacio multidimensional en sí). Por lo tanto, se puede ganar espacio al normalizar una dimensión, pero ganaremos espacio en el volumen relacional desde el que se carga el cubo, no en el cubo en sí. Para profundizar en este aspecto, os recomiendo que leáis el artículo "A trio of interesting snowflakes", de Ralph Kimball (http://www.intelligententerprise.com/010629/warehouse1_1.jhtml)
  • El diseño en estrella es más rápido: Esta frase hay que saber comprenderla. La velocidad de consulta del cubo no depende del diseño relacional de la dimensión, porque el motor multidimensional estructura los datos con respecto a dimensiones, no con respecto a las tablas que representan una dimensión. Cuando se "puebla" una dimensión, se leen los posibles valores que podrá tener una coordenada con respecto a esa dimensión, y se generan los correspondientes niveles. Evidentemente, durante este proceso, si la proyección relacional de la dimensión está normalizada, habrá que realizar tantas joins como tablas contenga la dimensión para ir poblando los distintos niveles de la dimensión. Hacer Joins es lento, y por eso se dice que el modelo en estrella es más rápido… pero OJO, SÓLO ES MÁS RÁPIDO DURANTE EL PROCESO DE CARGA DE LA DIMENSIÓN. Si nuestra dimensión es estática y jamás necesita ser regenerada, no se ahorra nada de tiempo. Cuidado con esto, porque podemos obsesionarnos con llegar a un modelo en estrella, y no darnos cuenta de que estamos complicando en exceso el ETL que "desnormaliza" los datos para llegar a este diseño en estrella… y recordad que el ETL se ejecuta sobre la base de datos OLTP, así que debería mantenerse tan eficiente como fuese posible. Para seguir profundizando sobre este tema, os recomiendo que leáis el epígrafe “Eliminate Joins between Fact and Dimension Tables” en la guía de optimización de Analysis Services (http://www.microsoft.com/technet/prodtechnol/sql/2000/maintain/ansvcspg.mspx)

Tanto hablar para no decir nada…

Efectivamente, todavía no me he decantado por ninguno de los dos diseños, y como inteligentemente habráis podido deducir, no me voy a decantar por ninguno. Hay que saber elegir inteligentemente dependiendo de la circunstancia. Habrá que valorar en cada caso:

  • Acceso al almacenamiento relacional subyacente. ¿Habrá aplicaciones o usuarios que accedan directamente al Datamart, sin hacer uso de la capa OLAP? En este caso, sin duda debemos decantarnos por una estrella. No sólo por la simplicidad, sino porque sacar cualquier informe relacional a partir de una estrella, requiere una única JOIN. Si el acceso siempre se realizará a través de una capa OLAP, nos da igual que el diseño sea en estrella o copo de nieve.
  • ¿Cómo son las dimensiones? Si son muy grandes, tienden a cambiar poco, y tienen atributos de gran tamaño y muy repetidos, tal vez interese considerar el espacio que ahorraríamos en el almacenamiento relacional usando un diseño en estrella.
  • ¿Complicamos mucho el ETL para transformar los datos en una estrella? Tal vez interese el diseño en estrella, porque de esta forma la carga de las dimensiones supondrá un esfuerzo para el sistema que soporta el datamart, pero descargaremos de trabajo a la base de datos de la que cargamos al propio datamart (recordemos que aunque el procesamiento sobre el datamart pueda ser incluso más lento, no afectará a los sistemas OLTP de la empresa).

Por último, los que usamos Analysis Services 2005 estamos de enhorabuena, porque al parecer, con esta maravilla de base de datos, el diseño en estrella apenas impacta en el rendimiento… bueno, eso al menos es lo que dicen en los blogs de MSDN (http://blogs.msdn.com/bi_systems/articles/164525.aspx).

A ver si con esto os animáis a mandarme comentarios… ¡que sería la primera vez que este tema no levanta polémica!

Optimizar la transformación Sort en SSIS

Uno de las tareas habituales a realizar con SSIS, suele ser la fusión de tablas que hubiesen sido particionadas horizontalmente en una única tabla. No estoy hablando de desnormalización, sino de los típicos casos en los que nos encontramos con una base de datos OLTP en la que por ejemplo, las transacciones comerciales de cada año han sido fraccionadas en diversas tablas. Para unir estos fragmentos, tenemos la transformación "Merge". El problema de la "Merge", es que requiere que ambas fuentes de datos se encuentren ordenadas con respecto a la misma clave. Aquí es donde surge la tentación de usar previamente la transformación Sort para ordenar estas fuentes.

¿Qué tiene de malo el uso de la Sort en estos casos? La Sort realiza la ordenación de los datos en la memoria del equipo que ejecuta SSIS… y esto puede ser bueno, o malo, según sea el origen de los datos. Supongamos que partimos de dos archivos de texto que contienen los datos desordenados… evidentemente, la Sort es una excelente opción en estos casos, ya que nos ordenará eficientemente los archivos (eso sí, a costa de un elevado consumo de memoria en el equipo que ejecuta SSIS). Sin embargo, ¿qué pasa si los datos vienen de tablas en una base de datos relacional? Alguno pensará que resulta un poco ridículo ordenar los datos en memoria, ¡cuando con una sentencia ORDER BY de SQL ya podemos traernos los datos ordenados! Quien haya pensado eso, está en lo cierto. Sin embargo, aunque traigamos los datos ya ordenados, la sentencia Merge se empeña en repetirnos una y otra vez que debemos usar la Sort. ¿Cómo podemos resolver este desaguisado?

Atentos a este truco del almendruco:

  1. Lo primero es traerse los datos ya ordenados de la base de datos. Para eso, recordad que cuando partimos de una fuente OLEDB, nunca es conveniente leer directamente de una tabla. Siempre es preferible utilizar una sentencia SQL en la que:
    • Nos traigamos únicamente los datos que necesitamos. Esto significa que sólo debemos traer a SSIS las columnas necesarias y la partición horizontal que necesitemos (si tenemos en una tabla las tallas de zapatos de nuestros futbolistas favoritos, y queremos obtener la lista de jugadores que calzan un número mayor que 42, haremos "SELECT DNI, Nombre, Apellidos, TallaZapato FROM Jugadores2003 WHERE TallaZapato > 42", NUNCA nos traeremos la tabla Jugadores completa). Esto hará que se reduzca el ancho de banda necesario para traernos los datos, y que al procesar menor volumen de datos en SSIS, éste pueda aprovechar de una forma más eficiente los buffers.
    • Usaremos la ORDER BY de SQL para ordenar los datos: "SELECT DNI, Nombre, Apellidos, TallaZapato FROM Jugadores2003 WHERE TallaZapato > 42 ORDER BY DNI". Por supuesto, ¡convendría que los datos estuviesen indexados en la base de datos con respecto a ese criterio!
    • Haremos lo mismo con el resto de tablas que queramos fusionar (en nuestro ejemplo, la tabla Jugadores2004).
  2. Aquí es donde empieza la parte interesante: haremos click con el botón derecho en las fuentes de datos, y seleccionaremos "Advanced options". En el nuevo diálogo que nos sale,  seleccionaremos "Input and output properties". En el árbol correspondiente, seleccionamos la salida estándar del nodo (Source Output). En el nodo principal de la salida, editamos la propiedad "IsSorted", y la ponemos a "true".
  3. Sin salir del diálogo de opciones avanzadas, seleccionamos la columna por la que hemos ordenqado el flujo (DNI) y alteramos la propiedad "SortKeyPosition". En esta propiedad debemos indicar qué posición ocupa la columna en la jerarquía de columnas que ordenan el flujo. En nuestro caso, el flujo está ordenado con respecto a un único criterio, así que la clave de esta columna sería "1".

Siguiendo estos pasos, ya podremos eliminar las transformaciones Sort, con lo que liberaremos una gran cantidad de memoria que bién nos vendrá para ejecutar otras tareas del ETL.

El inconveniente de este método está en que la SORT también nos permite eliminar registros duplicados, cosa que no podemos hacer de con este método que os he descrito. Es una pena que Microsoft no nos haya dado un transformación que elimine duplicados en un flujo de datos ordenado… sin embargo, esto es muy fácil de solucionar con un script. Para eso, tras la Merge podemos poner un script que compruebe la clave del registro actual con la del registro anterior, y desvíe los registros duplicados a la salida de errores (o simplemente añada al flujo un valor booleano, indicando si el registro está duplicado.

¡Felices transformaciones!

El XMLA es tu amigo

Sin entrar en discusiones filosóficas acerca de por qué el mundo OLAP no tiene interfaces estandarizadas, lo cierto es que quien da sus primeros pasos en este mundillo se encuentra con que los cimientos sobre los que se construyen las aplicaciones que atacan bases de datos relacionales, son unos débiles ladrillos de adobe en el mundo multidimensional.


¿Qué interfaz debe usar mi aplicación? ¿Cuales existen? ¿Para qué sirven?. Existen sobre todo dos grandes familias de tipos de acceso a bases de datos multidimensionales: aquellos que son interfaces relacionales con alguna extensión que los hace multidimensionales, y los que son puramente multidimensionales. El abanico de posibles mecanismos de conexión depende mucho de la base de datos que se utilice.


Practicamente todas las bases de datos multidimensionales permiten la conexión a través de interfaces relacionales. Las hay muy orientadas al mundo JAVA, que usan jdbc como estándar de conexión y SQL como lenguaje de query (por ejemplo Oracle), y las hay que ofrecen conexiones OLEDB u ODBC.


Acceder a un almacén multidimensional por medio de un API relacional siempre es un problema, porque sólo podremos acceder de esta forma a proyecciones bidimensionales de nuestra base de datos. Esto no significa que no podamos consultar datos estructurados en más de dos dimensiones… sólo significa que cuando los consultemos, al igual que al dibujar un cubo en una pizarra obtenemos una proyección plana, al consultar más de dos dimensiones también obtendremos una proyección aplanada (el resultado de realizar una multiplicación cartesiana de las distintas dimensiones que queremos representar).


Al final, en la interfaz de usuario sólo podemos mostrar dos dimensiones, así que uno podría pensar… qué rayos, me da lo mismo trabajar sobre un conjunto de datos aplanado. ¡No, no, y no! ¡Al aplanar un conjunto de datos multidimensional, hemos perdido gran parte de los metadatos que lo acompañan! Un volumen multidimensional que haya perdido su estructura, no nos permitirá realizar con comodidad operaciones de rotación o pivotado, así que precisamente estamos limitando en gran medida la capacidad de análisis que debería tener el usuario sobre esos datos. Vamos, que cualquier API que sólo permita acceder por medio de una interfaz relacional a un volumen multidimensional, no es más que una chapucilla para salir del paso.


Entonces, ¿qué alternativas nos quedan?


Muchos fabricantes tienen sus propias APIs no estándar que permiten acceder a conjuntos de datos multidimensionales… pero por suerte, también nos encontramos estándares.



  • Algunos estándares se utilizan para acceder a volúmenes multidimensionales utilizando un modelo de objetos. Seguro que podéis haceros una idea, ¿verdad? Instancio un cubo, me voy a la colección de dimensiones, ejecuto ciertas operaciones y me traigo un subconjunto del cubo con los datos que quiero. Oracle apuesta por este tipo de acceso, y como Oracle, todos aquellos que apuestan por JOLAP (http://jcp.org/en/jsr/detail?id=069). Yo veo un problema a este tipo de interfaces, y es que generalmente están ligados a que se desarrolle un determinado modelo de objetos (generalmente complejo) implantado en el lenguaje desde el que se lanzan las queries. Generalmente se desarrollan para un único lenguaje (en el caso de JOLAP es Java), aunque lo cierto es que desde que existen los servicios web, no tendría por qué ser así… ¿no creeis?.
    Microsoft también tiene una API de este tipo: la AMO (Analysis Management Objects), con la particularidad de que AMO sólo sirve para consultar los metadatos de una base de datos OLAP, y nunca para acceder a los datos en sí.
  • Microsoft lanzó en su día ODBO: OLE DB for OLAP. ODBO era una interfaz diseñada casi a medida de Excel, cuyo objetivo era permitir la conexión entre las «Pivot table» de excel y SQL Server Analysis Services. De hecho, a este proveedor OLE DB, se le llamaba también «Microsoft Pivot Table Services». Sin embargo, ODBO empezó a utilizarse para otros fines (por ejemplo, SAP incorpora una interfaz ODBO). Junto con ODBO, Microsoft lanzó un lenguaje de query para bases de datos multidimensionales: el MDX. ODBO transmite los datos en formato binario, a través de sockets TCP o encapsulado dentro de HTTP, pero siempre en formato binario. La pega que se le achacaba en su día a ODBO es el no ser lo suficientemente abierto.
  • En medio de esta guerra, surgió el XMLA como iniciativa de Microsoft. XMLA es un estándar abierto, basado en SOAP. XMLA ha sido rápidamente adoptado por un gran número de fabricantes de bases de datos multidimensionales (Hyperion, SAS, Mondrian…) salvo por Oracle, que lo tacha de estándar propietario de Microsoft. Podéis encontrar información sobre XMLA en www.xmla.org

¿Y por qué es XMLA nuestro amigo? Realmente el XMLA es el único estándar universal del que disponemos. XMLA no excluye a nadie, y puede ser implementado en cualquier lenguaje del mundo que permita programar y consumir web services. Microsoft, Hyperion y SAS ya tienen soporte XMLA, e incluso el mundo open source se está acercando a este estándar. En el mundo .NET, el cliente ADOMD.NET o incluso OLEDB for OLAP 9.0 son clientes XMLA, lo que les permite ir más allá de ser simples interfaces para acceder a Analysis Services y permitirles acceder en teoría a cualquier servidor XMLA (esto no siempre es así, pero no porque ADOMD.NET sea un cliente cerrado, sino porque muchas veces el soporte XMLA de las bases de datos no es lo suficientemente completo).


¿Qué razones hay para no apostar por el XMLA? La única razón es Oracle. Nos dicen que únicamente soportarán JOLAP, y que XMLA es un estándar cerrado de Microsoft. Es curioso que digan esto, ¡porque JOLAP y XMLA no son comparables! JOLAP y AMO sí que serían comparables, pero XMLA es un estándar que define la comunicación con la base de datos multidimensional a un nivel mucho más bajo que JOLAP. De hecho, JOLAP es un API, y XMLA es la definición de una interfaz orientada a servicios. JOLAP podría funcionar perfectamente sobre XMLA, utilizando un api en JAVA para lanzar consultas que se convirtiesen en llamadas «execute» de XMLA con sentencias MDX encapsuladas… bueno, esto no hace falta que lo diga yo, ¡es como actualmente funciona Hyperion!


Así que en esta película, si no nos queda más remedio que programar para Oracle, no nos quedará más remedio que rechazar el XMLA… pero hasta en este último caso, piensa que no hay ninguna razón para enemistarse con el XMLA. Es sólo que a veces las presiones y el politiqueo nos impiden elegir a nuestros amigos ;-).

No habrá versión 2007 de los Office Web Controls

A pesar de que voy un poco tarde con la noticia, allá va el bombazo del verano: Microsoft no sacará versión del 2007 de los Office Web Controls. No os perdáis el post y los comentarios del 17 de julio en el blog de excel 2007: http://blogs.msdn.com/excel/archive/2006/07/17/668544.aspx


Lo cierto del caso es que los OWC eran la alternativa más económica pra construir aplicaciones cliente de cubos OLAP, ya que permitían analizar datos de forma interactiva a cualquier usuario con licencia de Office, y más aún, permitían a los usuarios sin licencia de Office acceder a informes estáticos. Como alternativas, nos queda el desarrollo de aplicaciones basadas en Excel con las Visual Studio Tools for Office, o tal y como se propone en el blog, Microsoft Office SharePoint Server 2007. Bueno, u otras alternativas más caras como Scorecard Manager o los productos que ha adquirido Microsoft tras la compra de ProClarity en mayo.

Mondrian con OLEDB for OLAP 9.0. ¡Por fin se por qué no funciona!

Sin que sirva de precedente, voy a romper una promesa y antes de contaros por qué es tan importante el XML/A, voy a desvelaros el resultado de mis quebraderos de cabeza con Mondrian. Al final, tras mucho indagar, parece que el cliente OLE DB for OLAP 9.0 no funciona con Mondrian por el siguiente motivo:



  • Si la base de datos es SSAS en lugar de Mondrian, el cliente primero intenta establecer una conexión XML/A. Para eso, manda un comando EXECUTE vacío. SSAS le devuelve una respuesta XML/A que contiene un elemento «root» que a su vez está vacío, pero todo esto sirve para iniciar una sesión SOAP (ver los tag en petición y respuesta). A partir de aquí, el resto de mensajes XML/A llevan ese código de sesión. Al parecer, las sesiones SOAP son la base para conseguir que el funcionamiento del acceso a SSAS sea transaccional.


En cambio, con Mondrian pasa lo siguiente:



  • Mondrian devuelve correctamente la respuesta XMLA con el tag ROOT vacío… pero sin embargo, la respuesta SOAP no lleva el inicio de sesión en la cabecera (debe ser un error de Mondrian, porque J2EE sí que soporta sesiones SOAP) : 



  • Entonces, como el cliente no obtiene la respuesta esperada (no consigue iniciar una sesión), trata de realizar una conexión ODBO. Concatena «msolap.asp» a la URL del servlet XMLA de Mondrian y manda una petición ODBO. Lógicamente, como la URL no existe, Tomcat devuelve un error 404 (que es una página web, y no una respuesta ODBO). En ese punto, el cliente OLEDB devuelve un error a la aplicación. Conclusión… no tiene demasiada buena pinta… no parece que Mondrian soporte transacciones XML/A, y a lo mejor es ese precisamente el problema.


Para más información, os recomiendo que leais:


ODBO, XMLA y OLEDB for OLAP 9.0

La verdad es que pocos días me siento tan excitado como hoy. Hay veces que la información que se lee en Internet puede ser contraproducente, y me temo que he sido víctima de una de estas confusiones… ¿y dónde está la confusión? Bien… creo que será mejor que comience la historia desde el principio.
Llevaba días tratando de conectar mi base de datos Mondrian a los Office Web Controls sin éxito. ¿Por qué? Tratando de investigarlo, lei que los Office Web Control son clientes ODBO (OLE DB for OLAP) y que este es un protocolo binario y propietario de Microsoft, específicamente concebido para conectarse a Analysis Services. Bueno, esta es una verdad a medias… porque hay proveedores ODBO para otras bases de datos (por ejemplo SAP), pero esa es otra historia. Para conectar un cliente ODBO a una base de datos XMLA, es al parecer necesario un puente: el Simba O2X (http://www.simba.com/odbo-to-xmla.htm). Además, en la propia página de Simba, leí que Simba O2X no funciona con Mondrian, y que para Mondrian se está desarrollando un proyecto específico bajo el nombre de «Pentaho Spreadsheet Services» (todavía no está disponible). Vaya por Dios… Leoncio, nunca lo conseguiremos. Ya teníemos servido el clásico problema de la interoperatividad (parece mentira que pasen los años que pasen, la informática siempre se acabe enfrentando a los mismos problemas y tropezando con las mismas piedras, ¿verdad?). ¿Así que tendría que esperar a Pentaho Spreadsheet Services? Soy un ser de naturaleza impaciente… y necesitaba otra respuesta. ¿Cómo es posible que los Office Web Controls y Analysis Services no hablen el mismo idioma?
Al más puro estilo de Hollywood, me puse a espiar las conversaciones entre los Office Web Controls y Analysis Services… ¡y no podía ser! ¡Se veía XML! Bueno, todo hay que decirlo… antes de espiar este diálogo, configuré mi Analysis Services 2005 para permitir el acceso a través de HTTP, así que SQL Server y los OWC estaban hablando por HTTP, y yo estaba ahí, agazapado, escuchándolos. Entonces fue cuando vi el XML. Por cierto, para hacer accesible SQL Server Analysis Services a través de HTTP, sólo tienes que seguir estos pasos:
http://www.microsoft.com/technet/prodtechnol/sql/2005/httpssas.mspx
¿Qué significaba ese XML que NO debía estar ahi? ¿Acaso el ODBO se encapsula en XML cuando se transporta a través de HTTP?
Os voy a desvelar las respuestas….


  • El cliente OLE DB for OLAP de Analysis Services 8.0 usa un protocolo binario. Si la conexión a Analysis Services se realiza a través de HTTP, a la URL que se le proporcione al cliente OLE DB, se le añade la página «msolap.asp» y a ésta página, se postean los mensajes en un formato binario. El user Agent con el que se identifica el cliente es «Light DCube».



  • El cliente OLE DB for OLAP de Analysis Services 9.0 es nativo XMLA al menos cuando habla con Analysis Services 9.0. Eso significa que en teoría, los Office Web Controls conectándose a través del cliente OLE DB 9.0, deberían poder hablar directamente con cualquier base de datos XML/A (por ejemplo Mondrian)

En la práctica no he conseguido comunicar Mondrian con los Office Web Controls, probablemente porque el soporte XMLA de Mondrian 2.1.1 no es tan completo como el de Analysis Services, pero el simple hecho de descubrir que el proveedo OLE DB for OLAP de Analysis Services 9.0 habla XMLA, me ha alegrado el día. Lo cierto del caso es que en ningún sitio pone que el cliente OLE DB sea XMLA… siempre se da como referencia de cliente XMLA el ADOMD.NET, de hecho en muchos sitios hablan de ADOMD como cliente XMLA y OLE DB como cliente ODBO. Pues bien, ¡ahora ya sabéis que también las aplicaciones que utilizan clientes OLE DB pueden comunicarse a través de XMLA! Si alguien de Microsoft me lee y estoy equivocado, por favor que desmienta esta barbaridad… bueno, o que la confirme. Los que sepáis de qué hablo, os alegraréis porque es una gran noticia. Los que todavía os estéis preguntando por qué me siento tan feliz hoy, tendréis que esperar a mi próximo post, que os adelanto que se titulará «XML/A es tu amigo».

Compilando Mondrian (2ª parte)

«last updated July, 2005». Así comienza el documento titulado «Guide for Mondrian developers» (http://mondrian.sourceforge.net/developer.html). Para que os hagáis una idea, los binarios de Mondrian 2.0.1 están compilados en diciembre de 2005, y los de Mondrian 2.1.1 el 30 de mayo de 2006. Si es que la documentación no sirve para nada si no se actualiza… Llevo varios días tratando de compilar Mondrian usando este documento, y de momento he descubierto ya los siguientes errores:
  • En la documentación menciona que se debe establecer la variable de entorno «TOMCAT_HOME», apuntando al directorio de instalación de Tomcat. Sin embargo, en el «build.xml» para el ANT se aprecia que la variable de entorno de la que se obtiene el path de TOMCAT debe ser «CATALINA_HOME», y no «TOMCAT_HOME».
  • Hay un archivo BAT (indocumentado) llamado «build.bat», que aparentemente establece el CLASSPATH para que se pueda compilar Mondrian sin problemas… sin embargo, no funciona si el ANT se ha instalado en un directorio que contenga espacios (por ejemplo, si cuelga de «program files»). El fallo es fácil de corregir; sólo hay que poner unas comillas en la línea que lanza «ANT.EXE» al final del script. Sin embargo, a pesar de esta corrección, el build.bat sigue sin funcionar… así que lo he descartado y he seguido los pasos que indica la documentación (lanzar directamente el ANT).
  • A pesar de que leáis lo contrario en muchos sitios, con Mondrian 2.1.1 se debe usar XALAN 2.7, y NO 2.6. En muchos sitios se indica que se debe usar Xalan 2.6, pero esta información es válida sólo para Mondrian 2.0.1. En la documentación de Mondrian, para variar, no se da ninguna información al respecto. Este detalle es importante, porque la jerarquía de paquetes de Xalan 2.6 y 2.7 es totalmente distinta. Hay que usar el paquete correcto para evitar las «ClassNotFoundException».
  • Tampoco se menciona cual es el CLASSPATH que se debe utilizar para compilar Mondrian… por el método de ensayo y error, y gracias a la página «http://www.jarfinder.com/» (no se qué sería de mi sin ella), de momento he llegado a la conclusión de que deben añadirse al Classpath:
    • xml-apis.jar (es parte de la distribución de XALAN)
    • xercesImpl.jar (es parte de la distribución de XALAN)
    • javacup.jar (viene con el propio Mondrian, pero por algún extraño motivo, hay que meterla explícitamente en el CLASSPATH).
    • commons-math-1.1.jar (hay que descargársela del proyecto Jakarta). Con Mondrian ya viene la commons-math-1.0.jar, pero a mi al menos, no me funciona con esta librería. De nuevo, parece que el proyecto usa clases que no están en esta versión de la librería… así que conviene actualizarla.
  • Si os estáis tratando de compilar el paquete «ZIP» de Mondrian que se descarga de Sourceforge, tened en cuenta que le falta un archivo que resulta crítico: %MONDRIAN_HOME%srcmainmondrianrolapaggmatcherDefaultRules.xml. Descargadlo del sistema de control de fuentes Perforce, porque es imprescindible. De todas formas, es conveniente que se descargue TODO del Perforce, porque en el ZIP de la distribución faltan un montón de archivos (practicamente todas las queries que se utilizan en los tests unitarios).
  • Es recomendable usar JDK 1.5 y Tomcat 5.5 (aunque también funciona con JDK 1.4 y Tomcat 5.0, el parser XML de JDK 1.5 aparentemente corrige el bug relacionado con el «Byte Order Mark» que os comentaba en mi post anterior).
Siguiendo los pasos de la guía de Mondrian, y con estas notas que os he indicado, probablemente consigáis compilarlo (a mi al menos me han funcionado). Eso sí, si habéis partido de los fuentes descargados desde SourceForge, veréis que 71 tests unitarios fallan. No os empeñéis en intentar pasar los tests con esta versión… sencillamente, jamás funcionarán debido a que a la distribución de Mondrian 2.1.1 de Sourceforge le faltan 71 archivos (además del ya mencionado «DefaultRules.XML»). Yo os recomiendo que partáis de los fuentes directamente descargados del servidor de control de fuentes Perforce que ofrece el equipo Mondrian.
Para compilar los tests unitarios, tenéis que tener en cuenta que además de los pasos que se indican en la guía para desarrolladores, necesitaréis:
  • jUnit versión 3.8.x (con la 4.x no funciona). El JAR correspondiente debe añadirse al Classpath.
  • XMLUNIT 1.0. El JAR del XMLUnit debe estar en el CLASSPATH.
Con estos pasos ya deberíais poder compilar vuestras propias versiones de Mondrian. Para además de compilar, poder ejecutarlo de forma controlada y poder depurar lo que está pasando, os recomiendo que creeís un proyecto Eclipse partiendo del «build.xml» de Mondrian. Hay infinidad de páginas que enseñan a depurar servlets de Tomcat con Eclipse… os recomiendo esta: http://javaboutique.internet.com/tutorials/three/index.html

Compilando Mondrian (1ª parte)

Estamos desarrollando una aplicación que debe funcionar sobre bases de datos Oracle y SQL Server. La aplicación estará hecha en .NET… y aquí es donde comienzan todos mis problemas. No comprendo la estupidez de Oracle al cerrarse al estándar XMLA, pero esa es otra historia como para empezar un nuevo post. El caso es que se nos ha ocurrido usar Mondrian como una capa ROLAP con una interfaz XMLA que nos permita usar ADOMD desde nuestra aplicación .NET. Pues bien: ya llevo dos semanas con ello y cada vez estoy más desesperado.
La documentación de Mondrian es pésima y plagada de errores. He conseguido poner en marcha Mondrian 2.0.1, y me he llevado la desagradable sorpresa de que:

El caso es que quiero probar Mondrian 2.1.1, a ver si mejora el soporte XMLA. El problema de Sun lo resolveremos probablemente parcheando Mondrian para que ignore el BOM en los mensajes SOAP (eso que parece una chapuza, es la solución que recomienda Sun… es vergonzoso). Bueno, a lo que vamos… No he conseguido que la distribución binaria de Mondrian funcione en lo referente a XMLA (da una excepción «unable to internalize SOAP message»). Tras volverme loco tratando de poner en marcha la distribución binaria (sin éxito) llegué a la conclusión de que tal vez depurando Mondrian conseguiría ver algo, y para eso, el primer paso es compilar Mondrian.

Pues aquí me tenéis, compilando Mondrian. Ahora mismo compila, pero no pasa los tests unitarios… en serio, creedme que Mondrian es la cosa más desordenada que he visto en mi vida. En ningún sitio se indican las versiones adecuadas de las librerías que se deben usar en su compilación, apenas hay información en Internet, hay librerías que estoy viendo que son necesarias y de las que en los documentos ni siquiera se menciona su existencia, archivos que faltan y hay que bajárselos directamente del sistema de control de fuentes… en fin, a años luz de cualquier proyecto comercial (incluso a años luz de Oracle).

Ya os iré contando…

A ver si saco un ratillo y escribo un «howto» sobre cómo compilar Mondrian 2.1.1… bueno, ¡si consigo que pase los tests unitarios tras la compilación!