martes, 4 de noviembre de 2008

Best Practices en QlikView: cuando empieza a crecer el número de documentos en el servidor


En mi empresa llevamos 5 años utilizando QlikView como he comentado en algún otro artículo y puedo asegurar que cuando lo compré no tenía la más remota idea de lo que podría llegar a convertirse para ciertas personas y los problemas que iba a lucionarso con este producto. Lo compramos un poco para probar como aquel que dice.


Como todo, esta situación tiene un lado bueno, y otro malo.

El bueno: la de pasta gansa que nos hemos ahorrado en horas de programación de informes con el sistema operativo actual.

La mala: esto ha llevado a una situación un tanto caótica en cuanto al volumen de documentos que hemos llegado a generar y, en bastantes casos, el volumen se mide en cientos de MB comprimidos.


Otro factor siempre presente en nuestra vida, además del tener que comer, dormir, y...., son las prisas. Este último factor nos ha llevado a la situación que actualmente tenemos: infinidad de documentos que no están relacionados entre sí, que se recargan de forma separada cada día, con información redundada y que comienza a hacerse insostenible sus modificaciones (campos, tablas, etc). Con lo cual me enfrento, después de una cierta experiencia, con problemas de "sostenibilidad". La versión 32 bits además acentúa los problemas de los usuarios con algunos problemas de memoria ajenos a QlikView y que son imputables a la arquitectura de gestión de la memoria en máquinas windows de 32 bits (en fin, otro cantar).


Por resumir, inconvenientes:


  • Una lista de tareas programadas interminable recargando documentos diariamente, incluso cada hora.

  • La información está redundada en algún caso más de 15 veces (por ejemplo, la tabla "ARTICULOS")

  • Modificar, añadir, o eliminar un campo de una tabla (ARTICULOS por ejemplo) supone repetir n veces la modificación de este campo en cada documento que contenga esta tabla. En algún caso, los documentos han sido hechos por personas diferentes con lo que os podéis imaginar.

  • Las estructuras internas de tablas son diferentes en distintos documentos. Esto supone un problema sobre todo cuando se dispone de licencias Profesional o Enterprise (o en la versión nueva 8.5 si se habilita la creación de objetos compartidos de servidor) y los usuarios pueden ver los campos. Imaginad explicar a un usuario diferentes arquitecturas para la misma BD, un desastre...

  • No queda ventana de horas disponible por la noche para ejecutar todas las recargas de documentos. Ejemplo: 10 documentos que tarden 1 hora en recargarse = 10 horas.

Todos estos problemas y algún otro más, los hemos pasado en mi empresa por lo que voy a intentar hacer una especie de documento de buenas prácticas (o "Best Practices") para la creación y mantenimiento de numerosos documentos en un servidor. Me gustaría no ser el único que hace anotaciones en esta entrada y que aportéis vuestras ideas o soluciones:


"Best Practices" para la sostenibilidad de documentos grandes de QlikView:



  1. Piensa antes de hacer. Creo que el más importante. Pensar y estudiar lo que se pretende con el documento y si ya tenemos otro con datos similares. Es posible que convenga ampliar el existente y no crear uno nuevo.

  2. Archivos QVD. QlikView hace ya tiempo que inventó estos archivitos. La ventaja es que los recargas una vez y que tarde lo que tarde. Desde tu nuevo documento de QlikView puedes recargar tablas enteras alojadas en estos archivos QVD como si se tratasen de un excel o archivo de texto, con las siguientes ventajas: 1.- Velocidad (es entre 10 y 100 veces más rápida la recarga de un archivo QVD que un equivalente en otro formato) y 2.- La estructura de campos es única y hay un único punto de mantenimiento.

  3. Recargas Parciales: Es aconsejable utilizar la sentencia "Partial Load ..." para ganar en velocidad de recarga.

  4. Invierte más horas en el script de carga y menos en formulación extraña en los objetos y en código en el editor de módulo: Ganarás en velocidad de cara al usuario al tener el dato ya pre-calculado. Créeme, el usuario notará que vuela al hacer selecciones, bookmarks, etc...

  5. Utiliza la sentencia $(include=""). Puedes dejar fuera de QlikView fragmentos comunes entre varios documentos para que modificarlo sea cosa de abrir el notepad. Además (que me perdone la gente de QlikView) pero otras personas de tu departamento podrán mantener código de script genérico sin necesidad de tener acceso a la aplicación (evidentemente nos ahorramos unas pelillas...;-). Ni que decir tiene que deben primero controlar y conocer lo que tocan...

  6. Oculta las pestañas. Esto se lo ví a un gran amigo (http://http://www.cmigestion.es/) y me dió la idea perfecta para documentos de mucho contenido (muchas pestañas). Una primera hoja con una especie de menú te va a permitir que el usuario navegue de una forma controlada para obtener lo que necesita, frente a mostrar todas las pestañas y que vaya entrando en información que no le es necesario en ese momento. (Estoy preparando un documento que explique esto para una próxima entrega).

  7. Los nombres de campos claritos: Sobretodo si sois varias personas manteniendo los documentos. QlikView tiene la posibilidad de cualificar o no los campos de las tablas. Una buena especificación a la hora de llamar a los campos por su nombre puede ahorrarnos muchos dolores de cabeza, os lo aseguro. Los campos del tipo "CArtN" son menos descriptivos que "Costo Neto Articulo". Es triste decirlo pero más triste es robar ;-)

  8. NO al editor de módulo: QlikView desaconseja encarecidamente su uso salvo excepciones, claro está. Entre que el editor no lo tienen muy currado y que en posteriores versiones no te garantizan al 100% su correcto funcionamiento, muerto el perro, se acabó la rabia...

  9. Be graphic, my friend... Uséase, que como todo en esta vida, es importante hacerlo bien, pero casi más importante es venderlo bien. ¿No conocéis el típico en la empresa que no hace grandes cosas pero que las sabe vender?. Si tenéis un departamento de diseño gráfico o, simplemente alguien con un poco de gusto estético, no dejar al informático de turno hacer con vuestra obra de arte a presentar a dirección, un cuadro de Miró (con todos mis respetos...).

  10. Let's Backup. Backup, backup y más backup....

Estos son consejos a la hora de hacer un documento. A la hora de montar la estructura de carpetas NTFS en el server yo lo tengo montado de la siguiente forma:


RAIZ



  • QVD (carpeta con archivos QVD)

  • SCRIPTS (carpeta con permisos NTFS selectivos para modificar partes de ciertos script de carga)

  • DOCUMENTOS (esta es la carpeta pública a la que tienen acceso los usuarios y que contiene a su vez, subcarpetas y archivos QVW)

  • LOGS (carpeta con archivos logs del servidor, archivos .mem, etc...)

Esta parte es un ejemplo pero que podéis montarlo cómo queráis. QlikView tiene más opciones como la posibilidad de montar en el servidor de QlikView otras carpetas con rutas diferentes.


Un saludo

domingo, 2 de noviembre de 2008

Aplicaciones prácticas Qlikview: ¿Cómo hacer que el usuario compare 2 volúmenes de datos a su libre albedrío?


Hola. Con esta entrada voy a comenzar a explicar una serie de aplicaciones prácticas utilizando QlikView 8.5 que podéis aplicar en vuestras aplicaciones. Algunas de estas están extraídas de los mismos ejemplos que se pueden descargar de la web de QlikView (http://www.qliktech.com/) como la que voy a publicar a continuación.



El ejemplo consiste en utilizar funcionalidad nueva para permitir que, en una gráfica (por ejemplo), el usuario pueda comparar 2 conjuntos de valores diferentes para un campo determinado.


En el ejemplo tenemos ventas por productos y queremos que el usuario pueda comparar todas las ventas de una serie de productos, con otra suma de otros productos. Estos dos conjuntos, como cosa interesante, los crea el usuario en tiempo de ejecución.



En este ejemplo vamos a tocar los siguientes aspectos:


  • Set Análysis: Este ejemplo se resuelve de una forma más "rentable" utilizando esta nueva funcionalidad de lógica de conjuntos.



  • Editor de módulo: para definir los conjuntos, utilizaremos 2 pequeñas funciones de código para rellenar los valores de 2 variables definidas en el documento.



  • Variables de documento: utilizaremos 2 variables para almacenar las selecciones del usuario para el "GRUPO 1" y para "GRUPO 2".



  • Editor de script de carga: utilizaremos la sentencia LOAD InLine para realizar una carga de datos internos al documento, es decir, cargamos "a piñón" unos datos de venta para unas categorías que también se cargará con la sentencia InLine. Podríamos haberlo hecho con una excel o una tabla de SQL.

Os recomiendo que practiquéis con un documento nuevo y lo hagáis desde cero. Para ello cargaremos unos datos ficticios de venta en el script utilizando la sentencia "InLine".


Menú "Archivo" > "Nuevo"


Creamos las 2 variables que , más tarde, utilizaremos llamadas "Seleccion 1" y "Seleccion 2" y no definiremos ninguna regla de entrada y las dejaremos tal cual.


Menú "Configuraciones" > "Propiedades del documento" > "Variables" > "Nueva"


"Ctrl + Alt + D"


Abrimos el editor de script ("ctrl + E") y creamos 3 tablas: "CATEGORIAS", "ARTICULOS" y "VENTAS" utilizando las siguientes sentencias:


CATEGORIAS:


Load * inline[IdCategoria, Categoria


1,Bebidas


2,Snacks


3,Sopas


4,Postres


5,Golosinas];



ARTICULOS:


Load * inline


[IdArticulo, Nombre, IdCategoria


1,Zumo Naranja,1


2,Zumo Tomate,1


3,Coca-cola,1


4,Tea,1


5,Cacahuetes,2


6,Pipas,2


7,Gusanitos,2


8,Sopa de verduras,3


9,Sopa de fideos,3


10,Profiteroles,3


11,Tarta de arándanos,4


12,Tarta de queso,4


13,Chicles menta,5


14,Chicles fresa,5];




VENTAS:


Load * inline


[fecha,IdArticulo,Importe


01-01-2008,1,200.5


01-01-2008,3,150


01-01-2008,2,75


01-01-2008,5,10


01-01-2008,6,15


01-01-2008,9,250


01-01-2008,10,100


01-01-2008,11,90


01-01-2008,12,140.5


01-01-2008,14,25


02-01-2008,1,100


02-01-2008,3,45


02-01-2008,4,30


02-01-2008,6,4


02-01-2008,7,25


02-01-2008,10,100


02-01-2008,12,175


02-01-2008,13,5


03-02-2008,2,40.55


03-02-2008,3,50


03-02-2008,4,75


03-02-2008,8,34


03-02-2008,10,75


03-02-2008,11,74


03-02-2008,13,3];




Guardamos el documento en la carpeta que queramos, y ejecutamos el script.



Una vez finalizada la recarga del script, ahora vamos a crear un gráfico para comprobar que podemos sacar las ventas por categoría. Creamos un nuevo objeto de tipo "gráfico" y seleccionamos el tipo "gráfico de barras", seleccionamos la dimensión "Categoría" y como expresión "Sum(Importe)". El resultado se debería parecer a lo siguiente

A continuación, vamos a añadir a nuestra hoja un cuadro de lista para que el usuario pueda seleccionar los valores para el campo "Categoría" y hacer los grupos.

Añadimos 2 botones llamados respectivamente "Seleccionar Grupo 1" y "seleccionar Grupo 2".



Accedemos al editor de módulo (Ctrl + M) y creamos 2 rutinas



Sub Seleccion1
End Sub



Sub Seleccion2
End Sub



y las asociamos respectivamente a los botones anteriormente creados.



El código de las 2 rutinas es el siguiente:





Sub Seleccion1


set mySelections = ActiveDocument.fields("Categoria").GetSelectedValues
dim SelectedItems if mySelections.Count <> 0 then


for i = 0 to mySelections.Count - 1
SelectedItems = SelectedItems + """" + mySelections.Item(i).text +
"""" + "," next SelectedItems = left(SelectedItems,
len(SelectedItems) - 1)


set v = ActiveDocument.GetVariable("Seleccion 1")


v.SetContent SelectedItems,true


Else


set v = ActiveDocument.GetVariable("Seleccion 2")


v.SetContent "",true


End
if ActiveDocument.fields("Categoria").Clear


End Sub




Sub Seleccion2


set mySelections = ActiveDocument.fields("Categoria").GetSelectedValues
dim SelectedItems if mySelections.Count <> 0 then


for i = 0 to mySelections.Count - 1


SelectedItems = SelectedItems + """" + mySelections.Item(i).text + """" + ","


next


SelectedItems = left(SelectedItems, len(SelectedItems) - 1)


set v = ActiveDocument.GetVariable("Seleccion 2")


v.SetContent SelectedItems,true


Else


set v = ActiveDocument.GetVariable("Seleccion 2")


v.SetContent "",true


End


if ActiveDocument.fields("Categoria").Clear


End Sub



Una vez que ya tenemos el código y hemos asociado las rutinas a los botones ya estamos preparados para crear un gráfico que represente la suma de las 2 selecciones.



Creamos un gráfico sin dimensiones y le añadimos 2 expresiones




  1. Sum({$<[Categoria]={$(Seleccion 1)}>} Importe)



  2. Sum({$<[Categoria]={$(Seleccion 2)}>} Importe)


El truco está en que utilizando "Set Analysis" somos capaces de definir una selección fija independiente de las del documento, solo que como novedad, no tiene por qué ser una selección fija sino depender de una variable ("seleccion 1") que lo hace dinámico al usuario. Qlikview sustituirá antes de evaluar la expresión ( a esto se le llama expansión de una variable) $(variable) por algo como {"Postres","Bebidas", ...}.



El gráfico quedaría más o menos de la siguiente manera...


Ahora ya podéis comprobar el resultado para lo que debéis seleccionar varias categorías y entonces pincháis en el botón 1, volvéis a seleccionar otras categorías y pincháis en el botón 2 y váis viendo cómo cambia la última gráfica.


Además, podéis comprobar que aunque el usuario haga otras selecciones, la gráfica no cambia.


Para terminar vamos a agregar una línea de referencia en el gráfico que represente la media de las ventas, para esto editamos las propiedades del gráfico, en la pestaña "presentación", creamos una línea de referencia con la expresión
AVG({1} Importe).


Saludos.

sábado, 1 de noviembre de 2008

¿altruismo = egoismo?

quien fuera perro
Hola de nuevo y perdonad por el parón pero el trabajo me ha tenido bastante liado.


Esta semana, un amigo me hizo una pregunta que me ha hecho reflexionar y, aunque no tiene nada que ver con BI, sí que tiene mucho que ver con los bloggers y quería compartir mi opinión con vosotros a ver qué os parece.

La pregunta era "¿y tú qué ganas contestando a la gente que tiene dudas...?" y tiene una respuesta bien sencilla: puro egoismo ;-)


Efectivamente, yo diría que soy "egoista", me explico:


Mentiría diciendo que no espero nada y que soy altruista. Sinceramente no creo que exista alguien completamente altruista ya que, aunque sea en el fondo más interno de nosotros, siempre hay una razón que nos mueve a hacerlo. Siguiendo con este razonamiento, me atrevería a definir el altruismo como un tipo de egoismo, con la diferencia de que el altruista espera una recompensa moral o simplemente un bienestar producido por el reconocimiento social, una sonrisa, pero en el fondo es egoismo.


Este es mi caso, me voy a la cama pensando que he ayudado a alguien y que le he ahorrado el tiempo que yo perdí (o no) en aprenderlo.

Soy egoista, sí, al igual que toda la gente que desarrolla código open-source, los bloggers, son todos unos egoistas, al igual que los médicos, los ATS, los misioneros, algunos profesores, ...


Un saludo