Tip PENTAHO: comment modifier les traductions de l’interface Jpivot?

Voilà une astuce qui va être utile pour les développeurs et administrateurs de pentaho qui ont mis en place les pivots jpivot.
Vous avez surement remarqué   comme les traductions étaient des fois limites? Par exemple, la fonction dans la barre des outils de jpivot qui permet de supprimer les lignes vides a été traduite en « Opprimer les lignes blanches »:
Pas très compréhensible tout ça…
Et bien, il y a un moyen pour y remédier, c’est de faire sa propre traduction.
Pour cela, il va falloir modifier directement la librairie jpivot:
Allez dans biserver-ce/tomcat/webapps/pentaho/WEB-INF/lib et choisissez le fichier jpivot-XXX.jar
Ouvrez-le  avec votre gestionnaire d’archives préféré , puis allez dans le répertoire
com/tonbeller/jpivot/toolbar/resources
Là dedans vous allez trouver l’ensemble des fichiers de ressource qui servent à  l’affichage des tooltips dans la barre des outils. Ouvrez le fichier resources_fr.properties
nano resources_fr.properties
puis modifiez la ligne suivante :
toolb.non.empty=Opprimer lignes blanches
par :
toolb.non.empty=Supprimer lignes vides
Il n’y a plus qu’à  enregistrer le fichier de propriétés dans le jar et redémarrer PENTAHO et le tour est joué.

PENTAHO/JPIVOT: erreur à l’export Excel ou PDF

Maintenant que votre pivot est affiché, vous avez peut-être envie de l’exporter sous Excel pour retravailler les données.
Pour cela vous utilisez le bouton bien connu :

Sauf qu’au lieu de récupérer l’export vous êtes confronté à une erreur   du style :

mai 25, 2005 12:26:18 PM org.apache.catalina.core.ApplicationContext log
SEVERE: StandardWrapper.Throwable
java.lang.NoClassDefFoundError: org/apache/fop/configuration/Configuration
at com.tonbeller.jpivot.print.PrintServlet.init(PrintServlet.java:71)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1173)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:809)
../..
Caused by: java.lang.ClassNotFoundException: org.apache.fop.configuration.Configuration
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1645)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1491)
... 14 more
Tout cela est dû au problème de compatibilité descendante entre les dernières version de PENTAHO et jpivot.
Alors que PENTAHO intègre la dernière version de la librairie apache FOP, jpivot ( qui n’est plus maintenu depuis des lustres) utilise une version, disons-le, très ancienne.
Or, cette version ancienne version utilisait une classe (org.apache.fop.configuration.Configuration) qui n’existe plus dans la dernière version de FOP.
Il suffit alors de récupérer la version 0.20.5 sur un site ( maven par exemple)  et la copier dans
biserver-ce/tomcat/webapps/pentaho/WEB-INF/lib/:
cd biserver-ce/tomcat/webapps/pentaho/WEB-INF/lib/
wget http://mirrors.ibiblio.org/pub/mirrors/maven/fop/jars/fop-0.20.5.jar
Le bug a été référencé sur le JIRA de PENTAHO :
http://jira.pentaho.com/browse/BISERVER-7286
Ah oui, dernière chose,  n’oubliez pas de déplacer ou supprimer la librairie (fop-0.9XX.jar )fournie par PENTAHO.

Tip MySQL: "innodb_file_per_table" ou comment utiliser des fichiers de table séparés pour éviter le manque d’espace disque!!

Bon,
je suis pas très fier de ce que j’ai fait mais je vous relate mes erreurs et comment je suis arrivé à les résoudre pour vous éviter de faire pareil…

Situation

J’installe Mysql sur mon nouveau serveur dédié, monstre de calcul (8 cpu « machin » bridge) et d’espace disque ( 1To). Je configure ma base de données au format  Innodb ( le format qui permet les contraintes externes, etc.); je configure les capacités de mémoire, l’espace disque temporaire;
bref, je crois avoir tout passé en revue…

Puis j’alimente ma base avec des données provenant de réseaux sociaux – autant dire que la volumétrie est importante.

Out of space

Au bout de quelques semaines, je m’aperçoit que le fichier ibdata qui est dans le répertoire de données grossit mais ne rétrécit jamais , y compris lorsque je supprime des tables de plusieurs centaines de GigaOctets.
Finalement j’atteins la taille limite de mon disque et là je suis mal surtout que je dois produire des rapports d’analyse pour avant hier.

L’option de la mort qui tue

C’est là  que je m’aperçoit que par défaut à  l’installation,  MySQL et configuré pour gérer toutes les tables et leurs index dans un seul et même fichier –  le fameux « ibdata » et que ce fichier  est voué a grossir –  jamais à  réduire !
Il aurait fallu utiliser l’option « innodb_file_per_table » dans le fichier de configuration (my.cnf) pour que chaque table utilise son propre fichier de stockage des données et d’index.
Ok, je l’ai pas fait; mais alors comment faire pour rattraper ma bourde ?

Play it like a barbarian

Oui, je dirais qu’il faut y aller « à  la barbare » c’est à  dire faire une réinstallation des bases!
Première chose, faire une sauvegarde complète des bases : 

mysqldump -R -q -p --all-databases > 20120402_mysql_all.sql

Ensuite, arrêter MySQL et supprimer tous les fichiers du répertoire des bases de données( moi, je fais un move sur un support de sauvegarde):

service mysql stop
mv  /home/mysql/* /home/backup/mysql_old_dir

Redémarrer Mysql :

service mysql start

Enfin, restaurer les tables :

mysql -u root  < 20120402_mysql_all.sql

Je vous cache pas qu’il faut aimer avoir des sueurs froides dans le dos pendant quelques longues minutes.

N’hésitez pas à  commenter ce post si vous avez été dans le même cas ! 

Tip MongoDB: dompter MongoDB pour qu’il ne mange pas tout l’espace disque sous ubuntu 64!

Ma bête de course est en train de pleurer à cause d’un manque d’espace disque…
Mais que se passe-t’il donc?
Bon ok, lorsque j’ai fait l’installation d’Ubuntu 64 bits, j’ai paramétré la partition racine à 9 Gb, ce qui est un peu limite.

En utilisant Baobab, le programme de visualisation d’espace disque , je me suis aperçu que le fautif était MongoDB et plus précisément  son  système de journalisation:

Voici donc le moyen pour éviter de consommer de l’espace disque inutilement :

  1. arrêter mongodb :

    sudo service mongodb stop

  • éditer le fichier /etc/mongodb.conf et désactiver la journalisation :

    # Enable journaling, http://www.mongodb.org/display/DOCS/Journaling
    journal=false

  • supprimer les fichier dans le répertoire /var/lib/mongodb
  • redémarrer MongoDB:

    sudo service mongodb stop

Et voilà, votre partition ne va pas être inutilement remplie!

Un autre moyen est de déplacer le répertoire des données de /var/lib/mongodb vers une autre partition (exemple /home/mongodb) Pour cela éditer le fichier /etc/mongodb.conf et modifiez la ligne suivante :

# Where to store the data. dbpath=/var/lib/mongodb

en

# Where to store the data. dbpath=/home/mongodb

puis déplacer les fichiers qui étaient initialement dans /var/lib/mongodb vers le répertoire cible :

sudo cp -rv /var/lib/mongodb /home/mongodb/

Si vous aussi vous avez eu le même problème et que ce post vous a aidé, vous pouvez laisser un commentaire !

Limitation pentaho/mondrian: ne pas utiliser explicitement les clefs (key) pour les membres de dimensions dans les requêtes MDX

Bon, tout est dans le titre… mais, quand même, ça nécessite quelques explications et surtout des solutions de contournement.

La problématique

Si vous venez, comme moi, du domaine décisionnel « non libre » ( Microsoft Essbase, etc.) , vous avez sûrement l’habitude d’utiliser les clefs de membres des dimensions   pour les sélectionner  directement  dans les requêtes MDX.
Ok on fait un récap:
Lorsque vous faites une requête MDX, vous pouvez sélectionner un membre de dimension soit par sa valeur affichée ( en général le nom du membre), soit par la clef utilisée par le moteur OLAP. En général, la clef  utilisée et une clef numérique donc plus facile à  manipuler.

Un exemple, vite !!

Ok, disons que vous voulez mettre en perspective  les ventes  deux de vos produits phares :

  • les [casseroles en métal argenté(c)]
  • et  les [poêles dorées à l’or fin(TM)].

La requête MDX ressemblerait à  peu près à  ça :

SELECT {[ProductHierarchy].[casseroles en métal argenté(c)], [ProductHierarchy].[poêles dorées à l'or fin(TM)]} on ROWS,
 {[Measures].[sales]} ON COLUMNS
 FROM [Commercial]

Jusque là  tout va bien, sauf que en fait la même requête doit servir pour deux pays différents. Et pour chaque pays, le nom des produits est différent.
Plus précisément, en Angleterre les deux produits s’appellent respectivement : [silver metal pan(c)] et [gilded with fine gold pans(TM)]
Et là on a un problème:  la requête précédemment crée ne fonctionne plus telle quelle à  condition que les dénominations soient remplacées par leur traduction respective!
Du coup, en Angleterre la requête qui fonctionne est celle là :

SELECT {[ProductHierarchy].[silver metal pan(c)], [ProductHierarchy].[gilded with fine gold pans(TM)]} on ROWS,
{[Measures].[sales]} ON COLUMNS
FROM [Commercial]

Alors, comment faire pour que la requête MDX fonctionne correctement quelque soit le pays (et donc les traductions) ?

L’implémentation

C’est là  qu’en tant que super spécialiste de votre moteur OLAP préféré, vous allez utiliser les fonctions différentiation par la clef .
Dans notre exemple la casserole en argent a un N° d’identifiant numérique égal  à 112 et la poêle en or fin le N° 113, quelque soit les langages.

On utilise le caractère & ( « et commercial » ou « ampersand » en anglais) pour utiliser la clef à  la place du nom.
La requête devient alors :

SELECT {[ProductHierarchy].&[112], [ProductHierarchy].&[113]} on ROWS,
{[Measures].[sales]} ON COLUMNS
FROM [Commercial]

Ok, on met tout ça en pratique.

On crée donc  la dimension ProductHierarchy dans le cube Mondrian à  partir d’une table de dimension dénommée DimProduct avec deux champs  ProductKey ( notre clef)  et ProductName:

Le fait d’avoir rempli la propriété « column » avec le nom du champ « ProductKey » va permettre un certain nombre de choses, dont l’optimisation des requêtes SQL qui sont effectuées par le moteur de Mondrian, mais aussi la possibilité de faire notre requête sur la base de la clef ProductKey.

Mondrian Error  !!

Vous exécutez la requête et là, patatras  voilà ce que l’interpréteur de requête de Mondrian nous dit :

Mondrian Error:MDX object ‘[ProductHierarchy.New Hierarchy 0].&[113]’ not found in cube ‘Commercial’

La raison en est simple, Julian Hyde (le créateur de Mondrian ) n’a tout simplement pas prévu cette fonction dans son moteur.
Voici la preuve: un ticket a été référencé dans le gestionnaire d’incident de Mondrian sous la description :Member key treated as member name in WHERE

Arggh, voilà  donc une mauvaise surprise !  Pour enfoncer le clou, ce bug a été ouvert en 2009…

Vous pourriez me dire: « tu n’as qu’à  mettre le champ ProductName dans la propriété ‘column’ et on en parle plus ! ».
Oui, en effet ça marche mais :

  1.  la problématique de l’internationalisation reste entière.
  2. De plus, il faut savoir que le moteur Mondrian va utiliser la propriété « column » pour créer ses jointures lors des requêtes SQL sous-jaçentes ( rappelons-nous que Mondrian est un moteur ROLAP-  donc basé sur le moteur de base de données !). Or en général , il vaut mieux faire les jointure sur des champs de tables qui sont indexés , ne serait-ce que pour des questions  de performance et faire un index sur un champ numériques a beaucoup plus d’efficacité que sur un champ de type caractère.

Quelle est donc la solution ?

On va donc utiliser une fonctionnalité  qui ,elle, a été implémentée:  les propriétés en conjonction avec les filtres.
Dans un premier temps on va créer une propriété basée sur le champ « ProductKey »:

Et enfin on va utiliser un filtre , basé sur cette propriété

SELECT {Filter([ProductHierarchy].[Product].Members,
([ProductHierarchy].CurrentMember.Properties(« key »)=113)
OR
([ProductHierarchy].CurrentMember.Properties(« key »)=111))
} ON ROWS,
{[Measures].[sales]} ON COLUMNS
FROM [Commercial]

Là -enfin-, vous pouvez utilisez cette requête, quelque soit les traductions des produits utilisées.

Si vous avez déjà  été dans cette situation n’hésitez pas à  commenter cet article ou à  demander des précisions !

Tip Pentaho/kettle: accélérer le chargement de spoon PDI 4.3 GA

J’ai été assez désappointé par la dernière version de PDI ( Pentaho data integration) délivrée par Matt Casters en version 4.3 GA.
En effet, spoon, qui est l’interface de création des ETL, se charge en plus de 3 minutes montre en main !!!
Inacceptable dans ce monde speedé!!
Moi qui pensait que PDI était le seul truc de bien dans pentaho ( avec peut-être Mondrian) et bien j’en suis resté baba…

Et là  je me suis aperçu que je n’étais pas le seul dans cette situation. Ce qui  est assez déprimant c’est que le bug recensé n’est pas attribué, donc ne risque pas d’être résolu. Heureusement, Matt Casters himself , nous donne le work-around:

  1. Aller dans le répertoire data-integration/plugins/spoon, 
  2. puis supprimer le répertoire agile-bi et tout ce qu’il contient.

Miracle, spoon prend 40 secondes  à  charger ( ce qui est encore trop long, mais bon…) !
Par contre, du coup, toutes les fonctionnalités agiles de PDI ne sont plus disponibles (mais comme c’est du pipeau, c’est pas bien grave)

Bon par contre, Matt nous dit dans le forum qu’il travaille à la résolution de ce bug alors que le ticket en cours n’est pas attribué.

Hou, le menteur!!

Vagrant : Mise en place d’une box prête à l’emploi

Dans l’article précédent  (Veewee : La creation d’une boite Vagrant), nous avons vu comment créer une machine virtuelle prête pour Vagrant.

Considérons que nous avons avons ajouter la box à l’environnement Vagrant avec la commande :

vagrant box add 'myubuntubox' 'pathto/myubuntubox.box'
Si vous le souhaitez, je peux vous fournir une box Ubuntu 12.04 server X64.
Une fois, cette dernière ajouter à votre environnement, il convient de créer votre machine virtuelle en utilisant les commandes suivantes :
vagrant init 'myubuntubox'
vagrant up
vagrant ssh
Vous vous trouverez alors dans la machine virtuelle, sur laquelle vous pourrez installer vos outils de développement.
Le principe de Vagrant est similaire à celui du Cloud, vous avez soit un environnement vierge que vous vous paramétrez, soit un environnement prêt à l’emploi qui vous permet de fournir le même environnement à toute une équipe.
Pour ce dernier point, il convient d’utiliser un outil de provisionning, pour ma part, j’ai choisi Chef, mais il y en a d’autres comme Puppet .etc..

Dans le cas de Chef, on trouve de nombreuses recettes sur Github permettant d’installer à peu près tout, avec par exemple le repository officiel d’Opscode (https://github.com/opscode-cookbooks).

Afin de simplifier, un peu la vie de ceux qui veulent se lancer, j’ai préparer un petit projet qui vous permet de vous lancer : https://github.com/gpsnail/VagrantBox
Suivez les instructions du README pour commencer.

N’hésitez à me faire part de vos commentaires.