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 !