Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox



OLAP cube

Compatible Flex. Cliquer pour en savoir plus sur les compatibilités.Compatible ActionScript 3. Cliquer pour en savoir plus sur les compatibilités.Par wjm (Jean-Marc), le 02 mai 2009

Un cube OLAP est une représentation abstraite d’informations multidimensionnelles exclusivement numérique utilisé par l’approche OLAP (On-Line Analytical Processing). Cette structure est prévue à des fins d’analyses interactives par une ou plusieurs personnes du métier que ces données sont censées représenter. Les cubes permettent de dépasser les limitations des bases de données relationnelles, qui ne sont pas adéquates pour de l’analyse instantanée et l’affichage de grandes quantités de données. Du fait que le cube peut avoir plus de trois dimensions dans un système OLAP, on l’appel parfois hyper cube OLAP.

Les cubes OLAP ont les caractéristiques suivantes :

  • Obtenir des informations déjà agrégées selon les besoins de l’utilisateur.
  • Simplicité et rapidité d’accès.
  • Capacité à manipuler les données agrégées selon différentes dimensions.
  • Un cube utilise les fonctions classique d’agrégation : min, max, count, sum, avg, mais peut également utiliser des fonctions d’agrégations spécifiques.

Nous allons maintenant créer notre projet FLex à l’aide de Flex Builder pour cela il faut cliquer sur le menu File –> New –> Flex project, nommer votre projet « OlapCube ».

Nous utilisons dans notre projet un fichier XML de données qui se présentent de la forme :

 
<cube>
	  <data salesrep='Sophie' region='Sud-Ouest' product='Camembert' amount='12589' month='Sep' quarter='Q3'/>
	  <data salesrep='Bernard' region='Ile de France et Nord' product='Reblochon' amount='25986' month='Jun' quarter='Q2'/>
	  <data salesrep='Eric' region='Rhone-Alpes' product='Cantals' amount='9732' month='Jan' quarter='Q1'/></cube>

Il s’agit d’un fichier de données “plates” à partir duquel on va définir un schéma OLAP qui décrira comment les données vont être transformées d’une représentation plate à un cube OLAP.

Le schéma OLAP pour nos données définit 4 dimensions :

  • SalesRepDim
  • ProductDim
  • RegionDim
  • TimeDim

Ainsi que 2 mesures :

  • Revenue
  • Avg Revenue

Le schéma propre à nos données est le suivant:

 
<mx:OLAPCube name="Sales Data" id="cube" complete="cubeComplete(event)">
    <mx:OLAPDimension name="SalesRepDim">
      <mx:OLAPAttribute name="Sales Rep" dataField="@salesrep"/>
      <mx:OLAPHierarchy name="SalesRepHier" hasAll="true">
        <mx:OLAPLevel attributeName="Sales Rep"/>
      </mx:OLAPHierarchy>
    </mx:OLAPDimension>
 
    <mx:OLAPDimension name="ProductDim">
      <mx:OLAPAttribute name="Product" dataField="@product"/>
      <mx:OLAPHierarchy name="ProductHier" hasAll="true">
        <mx:OLAPLevel attributeName="Product"/>
      </mx:OLAPHierarchy>
    </mx:OLAPDimension>
 
    <mx:OLAPDimension name="RegionDim">
      <mx:OLAPAttribute name="Region" dataField="@region"/>
      <mx:OLAPHierarchy name="RegionHier" hasAll="true">
        <mx:OLAPLevel attributeName="Region"/>
      </mx:OLAPHierarchy>
    </mx:OLAPDimension>    
 
    <mx:OLAPDimension name="TimeDim">
      <mx:OLAPAttribute name="Quarter" dataField="@quarter"/>    
      <mx:OLAPAttribute name="Month" dataField="@month" />
      <mx:OLAPHierarchy name="TimeHier" hasAll="true">
        <mx:OLAPLevel attributeName="Quarter"/>         
        <mx:OLAPLevel attributeName="Month"/>     
      </mx:OLAPHierarchy> 
    </mx:OLAPDimension>
 
    <mx:OLAPMeasure name="Revenue" 
        dataField="@amount" 
        aggregator="SUM"/>
 
    <mx:OLAPMeasure name="Avg Revenue" 
        dataField="@amount" 
        aggregator="AVG"/>        
 
  </mx:OLAPCube>

Une datagrid OLAP est similaire à un pivot de table dans Microsoft Excel. Elle permet d’afficher des données agrégées dans une grille à 2 dimensions (ligne et colonne), comme une feuille de calcul, mais avec des données condensées basés sur les paramètres d’agrégations. Définissons dans notre projet notre datagrid OLAP, très simplement:

 
<mx:OLAPDataGrid id="odg" />

Nous allons donc premièrement charger ces données dans notre application à l’aide d’un URLLoader :

 
private function load():void {
	var loader:URLLoader = new URLLoader();                                
	loader.addEventListener(Event.COMPLETE, xmlLoaded);
	loader.load(new URLRequest("data/data.xml"));           
}

Une fois les données chargées dans notre application, il faut alimenter le data Provider du cube avec :

 
private function xmlLoaded(evtObj:Event):void {
	var model:XML = XML(evtObj.target.data);
	var list:XMLListCollection = new XMLListCollection(model.data);
	cube.addEventListener(CubeEvent.CUBE_COMPLETE,cubeComplete);
	cube.dataProvider = list;
        cube.refresh();
}

On ajoute l’événement “CUBE_COMPLETE” sur notre cube, afin d’exécuter la requête et récupérer le résultat pour alimenter le data provider du datagrid:

 
private function cubeComplete(e:Event):void {
	var query:IOLAPQuery = getQuery(cube);  
        if(query!=null){
	     var token:AsyncToken = cube.execute(query);  
             token.addResponder(new AsyncResponder(showResult, showFault));
	}
}
 
private function showFault(error:ErrorMessage, token:Object):void {  
            trace(error.faultString);  
}  
 
 
private function showResult(result:Object, token:Object):void { 
       if (!result) {  
             trace("No results from query."); 
             return;  
       } else {
             odg.dataProvider=OLAPResult(result);
       }
}

Nous devons maintenant créer une requête pour extraire les données agrégées depuis le cube, et les afficher dans notre datagrid.

Pour créer cette requête, il faut créer une instance de « OLAPQuery » et attribuer à ses 2 axes (ROW_AXIS & COLUMN_AXIS) les « OLAPSet » que l’on aura prédéfinis en fonction de ce que l’on veut analyser.

 
private function getQuery(cube:IOLAPCube):IOLAPQuery {  
        var query:OLAPQuery = new OLAPQuery;  
        var rowQueryAxis:IOLAPQueryAxis =  query.getAxis(OLAPQuery.ROW_AXIS);  
        var productSet:OLAPSet = new OLAPSet;  
        productSet.addElements(cube.findDimension("ProductDim").findAttribute("Product").children);  
        rowQueryAxis.addSet(productSet);  
 
        var colQueryAxis:IOLAPQueryAxis =  query.getAxis(OLAPQuery.COLUMN_AXIS);           
        var quarterSet:OLAPSet= new OLAPSet;  
        quarterSet.addElements(cube.findDimension("TimeDim").findAttribute("Quarter").children);  
        colQueryAxis.addSet(quarterSet);  
        return query;    
}

Dans cette première partie nous avons vu comment afficher le résultat d’un cube OLAP dans une Datagrid OLAP, ce qui était facile, puisque le dataProvider de la datagrid est du type “OLAPResult”, nous allons maintenant voir comment visualiser ce résultat dans un Flex chart, nous commençons par définir notre columnChart :

 
<mx:ColumnChart id="columnChart" height="100%" width="100%" showDataTips="true" >
	 <mx:horizontalAxis>
	        <mx:CategoryAxis id="catAxis" categoryField="key"/>
	 </mx:horizontalAxis>
</mx:ColumnChart>

Le résultats du cube étant un tableau à 2 dimensions, il faut donc faire des itérations à travers les 2 axes du cubes (row_Axis et column_Axis) afin de récupérer la valeur de chaque cellules et recréer notre propre array, que l’on pourra ainsi utiliser comme dataProvider pour notre chart.

	var colAxis:IOLAPQueryAxis = result.query.getAxis(OLAPQuery.COLUMN_AXIS);
        var colLength:Number = result.getAxis(OLAPQuery.COLUMN_AXIS).positions.length;
	var rowAxis:IOLAPQueryAxis = result.query.getAxis(OLAPQuery.ROW_AXIS);
	var rowLength:Number = result.getAxis(OLAPQuery.ROW_AXIS).positions.length;
	var newChartData:Array = [];
	var chartSerDP:Array=new Array();
	for (var i:int=0;i<rowLength;i++) {
		var rowTuple:OLAPTuple = rowAxis.tuples[i];
		var serie:String = rowTuple.explicitMembers.toArray().join(",");
		var mySerie:ColumnSeries=new ColumnSeries();
		mySerie.xField="key";
		mySerie.yField="value";
		mySerie.displayName=serie
		var serieDP:Array=new Array();
		for (var j:int=0;j<colLength;j++) {
			var colTuple:OLAPTuple = colAxis.tuples[j];
			var key:String = colTuple.explicitMembers.toArray().join(",");
 
			if(!isNaN(result.getCell(i, j).value)){ 
			     newChartData.push({key:key, value:result.getCell(i, j).value, serie:serie});
			     serieDP.push({key:key, value:result.getCell(i, j).value, serie:serie});
			}
		}
 
		        	mySerie.dataProvider=serieDP;
		        	catAxis.dataProvider=serieDP;
		        	chartSerDP.push(mySerie);
 
	}
	columnChart.series=chartSerDP;

Voici le lien pour télécharger le projet.

Amusez-vous bien !