[SSAS] Data Mining avec PowerPivot

Cela fait quelques temps que je voulais parler de l’intégration de deux features de SSAS liées à Excel: le Data Mining et PowerPivot, ou comment utiliser des données issues de PowerPivot avec les addins Excel de Data Mining (Table Tools et Data Mining Addin, sortis en 2007).

L’excellent Kasper de Jonge a sorti un super webcast résumant bien la technique. Le doublonnage d’informations n’étant pas mon dada je vais juste me contenter de vous donner la vidéo et de résumer le contenu pour les non anglophones.

Ceci dit – certes je suis un peu overbooké mais j’ai le temps de pondre un peu de réflexion – j’ai eu l’idée une petite feature qu’il a sûrement oublié d’aborder en fin d’article: combiner les expressions PowerPivot avec du DMX grâce aux fonctions Excel type DMPREDICT.

Alors voici l’objet:

Les addins Data Mining ne fonctionnent pas – encore? – sur des PivotTables (si vous avez fait du VSTO vous savez sûrement que la PivotTable est un objet très « à part » dans le modèle d’Excel), donc le but de l’affaire est de faire un Convert to formula d’une PivotTable d’analyse (qui va la convertir en sheet « Classique »), les expressions venant du cube étant alors spécifiées en tant que fonction CUBEMEMBER/CUBEVALUE qui prennent en paramètre des expressions « MDX » (notez les guillemets).

Dès lors utiliser les addins ne posent plus aucun problème, puisque vous êtes confrontés à des données « brutes », dont l’originie PowerPivotesque ne gène nullement l’analyse. A vous les « Analyze Key Influencers » et autres joyeusetés. Nota bene bene bene: les addins DM ne sont dispos qu’en… 32 bits donc oubliez le PowerPivot 64bits sur Excel 64bits. Espérons que cela changera…

Le tout petit rajout…

Bon en gros vous savez sûrement qu’il est possible d’appeller du DMX indirectement depuis une sheet Excel, basiquement cela a déjà été décrit par Bogdan Crivat (dont le départ chez Predixion fera aussi l’objet d’un post lorsque-j’aurai-plus-de-temps) dans ce post et qui peut être résumé ainsi:

La fonction Excel DMPREDICT permet de faire une requête de prédiction de type « simple » sur un modèle de mining dans Excel, elle a ce pattern:

DMPREDICT
(
« NomDeMaConnexionSSAS »,

« NomDeMonModele »,
« NomDeMaSortieDeModele »,
« NomParametre1 », « ValeurParametre1 »,
…,
« NomParametreN », »ValeurParametreN »
)

Il est donc parfaitement possible d’effectuer une requête DMX sur des données issues de PowerPivot et mises à plat en mode convert to formulas… et donc de marier DAX et DMX…

Publicités

[TD 2010] Webcasts

Les Webcasts des TechDays 2010 sont en ligne à cette adresse: http://www.microsoft.com/france/vision/mstechdays10/. Pour ma petite personne vous trouverez ci-dessous les deux sessions que j’ai eu le plaisir d’animer:

Celle sur la mise en place de cross-selling sur les sites e-commerce:

http://www.microsoft.com/france/vision/mstechdays10/Webcast-iframe.aspx?EID=1fa11288-4b1a-491a-a372-0a73f0e82dab

Et celle sur le CEP avec StreamInsight:

http://www.microsoft.com/france/vision/mstechdays10/Webcast-iframe.aspx?EID=da22183d-b064-4567-9cf8-d1bcb4a914f0

A bientôt et bon visionnage!

Local Mining Models depuis des modèles serveur

Je me suis une fois posé cette question simple: est il possible, à la manière d’un CREATE GLOBAL CUBE, de créer des modèles de mining locaux stockés dans des .cub (destinés à des applications embarquées) depuis des modèles serveur déjà développés.

Les applications seraient énormes pour des terminaux mobiles déconnectés, dont on mettrait à jour périodiquement un petit modèle d’analyse généré en central.

La réponse au problème est oui, d’où ce post, modulo un petit peu de travail. J’ai fait le boulot sous SSIS pour plus de clarté mais l’intégralité peut se faire depuis du code .NET.

1) Récupérer le script ASSL de création du modèle serveur

Dans une script task, un brin d’AMO suffit à récupérer ce script, grâce à l’objet Scripter utilisé par l’ami Management Studio.

 // Connexion au serveur
Server svr = new Server();
svr.Connect(---);

//Recuperation de la MiningStructure
MajorObject[] source = new MajorObject[1];
source[0] = (MajorObject)svr.Databases["Adventure Works DW 2008 EE"].MiningStructures["Targeted Mailing"];

//Instanciation d'un scripter
Scripter scr = new Scripter();
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;

//Ecriture en mémoire depuis un XMLWriter
StringBuilder sb = new StringBuilder();
XmlWriter writer = XmlWriter.Create(sb,settings);
scr.ScriptCreate(source, writer, true);
writer.Flush();
writer.Close();
svr.Disconnect();

//Affectation de la variable;
Dts.Variables["TempXMLAHolder"].Value = sb.ToString();
Dts.TaskResult = (int)ScriptResults.Success;

2) Retravailler le XMLA avec XPath

Le XMLA généré n’est pas très utilisable: il comprend encore des bindings aux DSV de la source, ainsi que des noms d’objets invalides. Un peu de DOM/XPath suffit à retravailler tout cela modulo la connaissance basique de XMLA.
De plus les modèles de mining embarqués ne supportent que les algos de clustering et de decision trees (les algos 2000), il faut donc supprimer les autres.

 string xmla = Dts.Variables["TempXMLAHolder"].Value.ToString();
string asDbName = Dts.Variables["SsasDatabaseName"].Value.ToString();

//Chargement du doc XML
XmlDocument doc = new XmlDocument();
doc.Load(new StringReader(xmla));
XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("Ns", @"http://schemas.microsoft.com/analysisservices/2003/engine");

//Changement de la base de données
doc.SelectSingleNode("/Ns:Create/Ns:ParentObject/Ns:DatabaseID", mgr).InnerText = asDbName;

//Suppression du binding de la MS à la DSV
XmlNode n = doc.SelectSingleNode("/Ns:Create/Ns:ObjectDefinition/Ns:MiningStructure/Ns:Source", mgr);
n.ParentNode.RemoveChild(n);

//Suppression des MiningModels non conformes
XmlNodeList l = doc.SelectNodes("/Ns:Create/Ns:ObjectDefinition/Ns:MiningStructure/Ns:MiningModels/Ns:MiningModel", mgr);
string algo = string.Empty;
for (int i = 0; i ; i++)
{
algo = l[i].ChildNodes[2].InnerText;
if (algo != "Microsoft_Decision_Trees" && algo != "Microsoft_Clustering")
{
bool b = true;
Dts.Events.FireInformation(0,
string.Empty,
"Le modèle doit être de type MDT ou MC, modèle de type " + algo + " supprimé.",
string.Empty,
0, ref b);
l[i].ParentNode.RemoveChild(l[i]);
}
}
Dts.Variables["TempXMLAHolder"].Value = doc.OuterXml;
Dts.TaskResult = (int)ScriptResults.Success;

3) Créer un cube local et appliquer l’ASSL dessus

Ceci fait il ne reste qu’à créer un cube local, grâce à la petite ruse de Chris Webb.
Puis à appliquer le script XMLA créé à ce cube (une simple AdomdCommand XMLA du script issu du Scripter AMO et retravaillé en XML).

On dispose alors… de modèles de mining dans un cube local!

4) Entrainer le modèle local

Mais il reste encore à les entraîner. Inutile de préciser que les tâches SSIS classiques sont inopérantes. Elles envoient des erreurs exotiques aidant à comprendre que leur usage devra être contourné.
Pour l’alimentation je suis passé par un paramètre DMX de type DataTable dans un INSERT INTO MINING STRUCTURE comme expliqué par Jamie McLennan dans un de ses posts pré-départ. Cette DataTable est dérivée du très oldschool ADO Recordset de SSIS – beuark – dans un script dédié. Modulo l’ordonnancement des colonnes pour la jointure naturelle voilà un modèle entraîné.

4) Action!

Il suffit alors de l’utiliser, en ADOMD.NET avec une chaîne de connexion pointant sur le fichier .cub en tant que Data Source et voici la « belle » application:


Le package complet est disponible ici et vous pouvez le tester. Il ressemble à cela:


En espérant avoir suscité quelques scénarii de mining embarqué…

A bientôt!

Réentrainement incrémental dans Analysis Services Data Mining

Une question qui m’est assez souvent posée: la possibilité ou non de procédéer à un apprentissage incrémental dans Analysis Services.
La réponse est nativement non contrairement au fait qu’en AMO les modèles disposent d’une propriété AllowIncrementalInsert qui peut être à true…
C’est un objectif à terme mais aujourd’hui ce n’est pas le cas.

Il faut donc ruser et dans ce type de problématique SSIS est encore une fois votre ami.

L’idée générale est d’activer le DrillThrough dans le modèle considéré et à chaque apprentissage de disposer de deux sources unionées:
– Les nouvelles données récupérées via une OLE DB Source
– Les anciennes données récupérées via une source OLE DB sur AS, avec une requêtre DMX du style

SELECT * FROM [Modèle].CASES

Voilà n’hésitez pas pour toute question.
A bientôt!

[SSAS] Utiliser les viewers Data Mining dans un BackOffice Winforms

Petit post très court pour donner des idées. Pour intégrer les viewers de modèles de Data Mining disponibles dans Visual Studio au sein d’Excel, les développeurs de Redmond ne les ont pas recodés. Ils ont simplement profité du fait que ceux ci sont disponibles en tant que composants Winforms et que vous pouvez faire de même, à savoir les réutiliser dans vos applications.
Il suffit pour cela de les ajouter à la Toolbox Winforms, en allant chercher l’assembly Microsoft.AnalysisServices.Viewer.dll qui doit se trouver dans le dossier Common7\IDE\PrivateAssemblies de votre installation de Visual Studio.

A vous les jolis backoffices!
A bientôt!

[SSAS] L’opérateur UNION manquant en DMX

Il vous est peut être arrivé de vouloir intégrer un Forecast généré avec Analysis Services Data Mining dans une application. C’est très joli à présenter, et ça l’est encore plus au sein d’un rapport Reporting Services.

Malheureusement, l’instruction PredictTimeSeries() qui gouverne la sortie d’un modèle de type TimeSeries ne permet que d’effectuer des sorties de données passées OU futures mais pas les deux mixées… Or l’ami Reporting Services ne supporte qu’un DataSet par DataRegion donc impossible de réaliser nativement une belle courbe avec le réel suivi du forecast…

Jamie Mc Lennan l’architecte du produit, propose sur son blog de réaliser une SP managée pour rempalcer PredictTimeSeries. Solution efficace et que j’ai déjà testé, mais qui masque à mon avis un problème de DMX, le manque d’opérateur UNION en n’adressant qu’une seule problématique induite.

En codant un petit bout de C# on arrive pourtant facilement à obtenir un pseudo opérateur union parfaitement fonctionnel, d’abord en écrivant une méthode d’exécution de code DMX renvoyée sous forme de DataTable:

private DataTable ExecuteQuery(string query)
{
using (AdomdCommand cmd = new AdomdCommand(query))
{
AdomdDataReader dr = cmd.ExecuteReader();
DataTable destinationDt = new DataTable();
DataTable schemaDt = dr.GetSchemaTable();
foreach (DataRow schemaDr in schemaDt.Rows)
{
destinationDt.Columns.Add((string)schemaDr["ColumnName"], (Type)schemaDr["DataType"]);
}

DataRow currentDr = null;
while (dr.Read())
{
currentDr = destinationDt.NewRow();
for (int i = 0; i < dr.FieldCount; i++)
{
currentDr[i] = dr[i];
}
destinationDt.Rows.Add(currentDr);
}
}
return destinationDt;
}

Qu'il suffit ensuite d'utiliser avec cette méthode:

private DataTable ForgeUnionDMX(params object[] dmxQueries)
{
DataTable t1 = this.ExecuteQuery(dmxQueries[0].ToString());
for (int i = 1; i < dmxQueries.Length; i++)
{
t1.Merge(this.ExecuteQuery(dmxQueries[i].ToString()));
}
return t1;
}

Malheureusement, et c'est le seul point que je n'ai pas réussi à résoudre, il semble qu'Analysis Services soit incapable de reconnaitre les procédures stockées acceptant un paramètre de type params (ParamArray en VB).
Ce n'est donc pas cette méthode qu'il faut exposer mais plutôt autant d'alias qu'on souhaite accepter de paramètres...

public DataTable UnionDMX(string dmxQuery1, string dmxQuery2)
{
return this.ForgeUnionDMX(dmxQuery1, dmxQuery2);
}
public DataTable UnionDMX(string dmxQuery1, string dmxQuery2, string dmxQuery3)
{
return this.ForgeUnionDMX(dmxQuery1, dmxQuery2, dmxQuery3);
}

Sale et dommage, mais inéluctable semble-t-il: Greg Galloway et Darren Gosbell ont fait de même à de nombreux endroits dans le projet ASSP.

Voilà à vous de coller ça dans un projet C# et de l'essayer: vous allez voir c'est très joli et cela constitue un argument assez immédiat en faveur de ce type d'applications

A bientôt.

[Jamie Mc Lennan] Comprendre le nommage des colonnes MDX en DMX

Astuce assez connue par les utilisateurs de DMX – inconnue de beaucoup donc! – mais sans laquelle je n’aurais jamais pu écrire sereinement le bout de code ci dessous. Celle-ci répond à la question suivante: comment deviner le nommage – barbare – des colonnes généré par la mise à plat du MDX, cela lorsque l’on prend un cube comme source de prediction join en DMX?

Tout simplement en faisant une requête comme ceci:

SELECT t.*
FROM [MyModel]
NATURAL PREDICTION JOIN
(
[MyMDXQuery]
) AS t

Le moteur renvoie alors le résultat mis à plat de la requête MDX et le nom des colonnes généré 🙂

Voilà, merci à Jamie et son équipe d’inclure ce genre de trick dans le langage. Vous pouvez (re) lire son papier ici.

A bientôt!