Techdays 2013, épilogue

TD13

Bonjour à tous, un petit peu crevé après cette préparation éreintante de session qui, d’après les premiers retours, vous a pas mal plu! Je vous rassure on s’est bien amusés avec le grand – autant par les New Rock que par le talent – Romu aussi. Sur un plan plus perso la préparation quelque peu tardive m’a empêché de venir aux sessions qui m’intéressaient mais avec Romuald nous avions des slides à finir à la force du poignet (oui je sais Aurélien ceci est une trèèès mauvaise blague, et sache que toute la salle était avec toi, bon rétablissement mon poulet!).

Merci en tous les cas aux présents, je pense à Pascale, Flo, David, Fab, Rom,  Dominique et j’en oublie, ainsi qu’à tous ceux qui sont venus nous faire leur retours à la sortie, ça fait chaud au coeur, vraiment!

Démos, Director’s Cut

Bon comme on a été un petit peu à la bourre je voulais revenir sur quelques démos histoire que les passages peu clairs le soient un peu moins. On va faire ça dans l’ordre, et ça concerne surtout la partie DaxMD, aussi connu sous le nom de PowerView for Multidimensional Models, CTP publique d’une version du moteur OLAP supportant le DAX, disponible ici. Au passage et ce depuis la session, David Joubert a posté un excellent test de la conversion de modèles tabulaires vers du MD qui fait un peu le même job que certaines de nos démos.

CSDL Metadata

On vous l’a dit, la raison pour laquelle on peut envoyer du DAX à un modèle multidimensionnel – qui permet à PowerView de s’y connecter – dans cette CTP tient en deux raisons

  • Un Formula Engine DAX côté multidimensionnel, capable d’interroger un SE MOLAP
  • Des métadonnées au format CSDL, le format normé de Microsoft introduit avec Entity Framework qui permet de décrire un modèle de données. Pour étendre le CSDL aux données d’analyse, Microsoft a publié une extension au CSDL nommée CSDL-BI.

Pour requêter les métadonnées CSDL, un Rowset XMLA (ou une DMV) existe. Il suffit de passer le nom de la base, du cube (oui car en multidimensionnel on peut avoir plusieurs cubes!) dans le champ… PERSPECTIVE_NAME (Oui bon c’est une CTP hein), et un champ non documenté, VERSION, qui dit que… qui dit 2.0. (Je vous ai déjà dit que c’est une CTP?) Voilà.

<Envelope xmlns=”http://schemas.xmlsoap.org/soap/envelope/”>
       <Body>
              <Discover xmlns=”urn:schemas-microsoft-com:xml-analysis”>
                     <RequestType>DISCOVER_CSDL_METADATA</RequestType>
                     <Restrictions>
                           <RestrictionList>
                                 <CATALOG_NAME>AdventureWorksDW2012Multidimensional-EE<CATALOG_NAME>
                                 <VERSION>2.0</VERSION>
                                 <PERSPECTIVE_NAME>Adventure Works</PERSPECTIVE_NAME>
                           </RestrictionList>
                     </Restrictions>
                     <Properties>
                           <PropertyList>
                                 <FORMAT>Tabular</FORMAT>
                           </PropertyList>
                     </Properties>
              </Discover>
       </Body>

PowerView comprend ça. Pas vous. C’est normal. Mais ça vous montre qu’on a dorénavant une couche de métadonnées dans SSAS (ce qui n’était pas le cas avant Tabular).

Drill-through en MDX, en DRILLTHROUGH ou en DAX?

Pour faire des extractions de détail en MDX, on a basiquement deux solutions. Faire des requêtes MDX bien barbares, ce qui est assez lent, mais pas compliqué à écrire (et au passage ce que génère Excel PivotTable ou SSRS au Designer).

SELECT
{
	[Measures].[Reseller Sales Amount]
}
ON 0
,
NON EMPTY
{
	[Date].[Date].[Date]
	*[Geography].[City].[City]
	*[Product].[Product].[Product]
	*[Reseller].[Reseller].[Reseller]
	*[Sales Territory].[Sales Territory Region].[Sales Territory Region]
}
DIMENSION PROPERTIES [Reseller].[Reseller].[Bank Name]
ON 1
FROM [Adventure Works]

Quand on est bon, on peut faire des requêtes de DRILLTHROUGH sur une cellule. Les vieux de la vieille du RS 2000 faisaient ça avec de l’OLE DB for OLAP dans SSRS (c’est faisable aussi avec le provider AS, mais en mode mining, éditeur coupé). Avantage: lent à la première exécution, mais monte bien en cache.

DRILLTHROUGH
SELECT
{
 [Measures].[Reseller Sales Amount]
}
ON 0
FROM [Adventure Works]
RETURN
 [$Date].[Date]
 ,[$Geography].[City]
 ,[$Product].[Product]
 ,[$Reseller].[Reseller]
 ,[$Sales Territory].[Sales Territory Region]
 ,[Reseller Sales].[Reseller Sales Amount]

Dans la session on vous a montré qu’on peut aussi faire ça en DAX. pour de l’extraction de détail, ça envoie sacrément (les temps de réponse sont en moyenne 10 fois meilleurs sur notre petite base d’exemple).

En plus cela semble constant au vu de nos tests contrairement aux autres modes d’accès.

Evaluate
(
	Summarize
	(
		'Reseller Sales'
		,'Date'[Date.Key0]
		,'Date'[Date]
		,'Geography'[City.Key1]
		,'Geography'[City.Key0]
		,'Product'[Product.Key0]
		,'Product'[Product]
		,'Reseller'[Reseller.Key0]
		,'Reseller'[Reseller]
		,'Reseller'[Bank Name]
		,'Sales Territory'[Sales Territory Region.Key0]
		,'Sales Territory'[Sales Territory Region]
		,"Sales Amount",'Reseller Sales'[Reseller Sales Amount]
	)
)
Order By
	'Date'[Date]
	,'Geography'[City.Key0]
	,'Product'[Product]
	,'Reseller'[Reseller]
	,'Reseller'[Bank Name]
	,'Sales Territory'[Sales Territory Region]

Vous noterez au passage les splendides Key0, Key1 dans la requête. Kézako? Et bien si vous vous y connaissez en member properties vous savez que les Key0…KeyN en MDX sont les KeyColumns d’un attribut. Pour développer DaxMD – de la même manière qu’il a du être difficile de faire rentrer le concept de DefaultMember dans un PowerPivot – cela n’a pas du être une mince affaire pour les équipes de Redmond de faire comprendre l’idée de clés composites et de NameColumn à du DAX . Moyennant quoi dès que la NameColumn est différente de la KeyColumn dans la Dimension, on doit spécifier cette dernière, sans quoi on prend un beau message d’erreur:

Column [Truc] is part of composite key, but not all columns of the composite key are included in the expression or its dependent expression.

Bon à savoir…

Rapport de drill en SSRS

Pour la suite de la démo, Romu a montré l’inclusion de ce code dans un Rapport SSRS  pour lequel il faut utiliser le mode DMX pour taper la requête (comme dans ce vieux post sur le Drillthrough). Les paramètres quant à eux sont évidemment gérés (Syntaxe @Paramètre) et le sous rapport envoyé grâce à un JumpToReport sur le camemb… l’histogramme.

DAX DrillThrough Action dans SSAS

Enfin la cerise sur le gâteau concernait l’exécution de ce code dans une action de type Rowset côté AS. L’idée étant d’avoir un Drill en DAX sur un cube. Une action de Rowset a une expression de type chaîne de caractère qui va être évaluée dans un bloc XMLA <Command>… qui contient normalement du MDX. Mais dans DaxMD, les Command peuvent être en DAX (oui c’est le principe), donc on peut y mettre la requête DAX précédente.

Problème: comme pour le DrillThrough on Calculated Members de Mosha on doit contextualiser la cellule (si je clique sur une cellule, la requête DAX doit être filtrée sur les dimensions autour). Dans son post, Mosha explique que:

In order for drillthrough to address the correct cell, we need to put current cell coordinates into the SELECT clause. One way of doing it would be to write long MDX string concatenation, using <hierarchy>.CurrentMember.UniqueName subexpression for every hierarchy in the cube. However, this is tedious and error-prone approach. There are hundreds of hierarchies, new ones can be added, old ones removed or renamed etc. Instead, we can just call stored procedure which will enumerate all the current coordinates (note that we could’ve done the same with the RETURN clause too).

Procédure que l’on ne possède pas ici (Mosha utilise celle de ASSP qui renvoie du… MDX). Ce que j’ai montré pendant la session c’est le principe de la chose appliqué sur une seule hiérarchie que les plus courageux d’entre vous finiront. (mais si un candidat se présente pour écrire une stored proc… :)). La partie importante de la requête est dans le Filter, qui va désactiver le filtre si on est au niveau All en générant une clause en DAX depuis du MDX. Oui je sais c’est tordu:

"Evaluate
(
	CalculateTable
	(
		Summarize
		(
			'Reseller Sales'
			,'Date'[Date.Key0]
			,...
		)
		,'Sales Territory'[Sales Territory Region.Key0] = "+[Sales Territory].[Sales Territory Region].CurrentMember.Properties('Key0')+"
        ||"""+[Sales Territory].[Sales Territory Region].CurrentMember.Name+"""="""+[Sales Territory].[Sales Territory Region].DefaultMember.Name+"""
    )
)"

Conclusion

Voilà c’était à peu près tout. Merci à tous pour votre présence, à vos commentaires si vous voyez une erreur. Quant au contenu, ce sera avant Vendredi sur mon SkyDrive, j’éditerai le post.

A bientôt!

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s