Eine Einführung anhand des MOLAP-Servers Palo

OLAP – mit Würfeln analysieren und planen

Michael Raue

Die Lücke zwischen Vorhersage und Realität von Finanzdaten eines Unternehmens ist nicht selten so groß, dass man durchaus den Eindruck bekommen kann, Planung und Analyse würden mit konventionellen Würfeln vollzogen. Das wäre zwar einfach in der Anwendung, aber schwierig in der Interpretation und daher anfällig für fehlerhafte Prognosen. Eine wichtige Voraussetzung für die gute Planung zukünftiger Vorhaben ist die effektive Analyse bestehender Daten aus operativen Systemen und das Erkennen von Mustern und Beziehungen – dafür werden OLAP-Datenbanken eingesetzt. Eine kostengünstige, weil Open-Source-Lösung ist hier der MOLAP-Server Palo, der sich der Java-Welt durch ein API erschließt.

Die Analyse von unternehmenskritischen Kennzahlen und die Ableitung von Entscheidungsgrundlagen fasst man unter dem Begriff Business Intelligence (BI) zusammen. Natürlich werden solche Analysen mit Software-Tools umgesetzt, und so entwickelte sich dieser Bereich in den letzten Jahren zu einem sehr dynamisch wachsenden Sektor der Software- und Beratungsbranche. Dies liegt an den gewachsenen Anforderungen an die Präzision und Aktualität des Berichtswesens – bedingt einerseits durch strengere gesetzliche Vorgaben und andererseits durch die immer schneller werdenden Innovationszyklen und die Veränderungszwänge in Unternehmen.

Ein wichtiges Hilfsmittel für die Analyse von operativen Daten und das Ableiten von Planszenarien sind OLAP-Datenbanken. Der Begriff OLAP steht für Online Analytical Processing. OLAP-Datenbanken unterstützen die reaktionsschnelle Abfrage, Verdichtung und Analyse von Datenbeständen eines Unternehmens. Man unterscheidet drei Formen von OLAP-Datenbanken: M(emory based)OLAP-, R(relational)OLAP- und H(ybrid)OLAP-Datenbank-Systeme.
Erstere speichert, berechnet und analysiert die Daten im Arbeitsspeicher, um optimale Performance zu erreichen, und stellt dazu eigene Datencontainer zur Verfügung. Damit dieses MOLAP-Konzept funktioniert, müssen die Daten natürlich schon bei der Transformation aus den Vorsystemen verdichtet werden, um die Speicherbelastung in überschaubaren Grenzen zu halten. ROLAP belässt die Daten in den relationalen Datenbanken und bietet Analyse- und Verdichtungsfunktionalitäten. Das bringt erhebliche Geschwindigkeitsnachteile bei der Auswertung, ermöglicht aber größere Datencontainer. HOLAP stellt einen Kompromiss zwischen beiden Technologien dar.

Besonderheiten von OLAP-Datenbanken

OLAP-Datenbanken speichern ihre Daten in so genannten Würfeln oder Cubes. Die Daten werden dabei nicht wie bei relationalen Datenbanken in einer Liste gespeichert, sondern in mehrdimensionalen Räumen, ähnlich einem mehrdimensionalen Array bei Computersprachen. Die Achsen dieser mehrdimensionalen Räume werden mithilfe von Dimensionen aufgespannt. Dimensionen bestehen aus benannten Elementen, entsprechend den Feldern einer relationalen Datenbank. Dimensionen bilden in der Regel Sachzusammenhänge ab, also Regionen, Zeit, Konten, Produkte etc. Die Dimensionen bilden die Achsen des Würfels. Eine Besonderheit von Dimensionselementen ist es, dass sie gruppiert werden können. Durch die Gruppierung wird nicht nur eine übersichtliche logische Ordnung erreicht, sondern es werden auch so genannte Konsolidierungen definiert. Hintergrund ist, dass die untergeordneten Feldinhalte, sofern es Zahlen sind, vom Datenbank-Server automatisch in die übergeordneten Feldinhalte aufsummiert werden. Im Gegensatz zu relationalen Datenbanken ist die Organisation multidimensionaler Datenbanken eher zellorientiert als zeilenorientiert. Entsprechend werden Daten auch durch die Definition der Zell- oder Array-Koordinaten identifiziert.

Abb. 1: Würfel oder Cube schematisch dargestellt

Ein wichtiges Feature von OLAP-Datenbanken ist, dass sie Berechnungsregeln oder Rules benutzen, etwa das bereits erwähnte automatische Aufsummieren von Elementen einer Dimension durch die Gruppierung. Zudem kann man Faktoren oder Formeln definieren, die für diese Aufsummierung genutzt werden. Weiterhin lassen sich auch Formeln für die Berechnung von Zellen oder Zellbereichen einsetzen, ähnlich wie bei einer Tabellenkalkulation.

Der Nutzen

OLAP-Datenbanken und darauf aufsetzende Reporting- und Planungs-Tools setzt man hauptsächlich im Controlling- und Sales-Bereich ein. Die aufbereiteten Daten können schnell aus unterschiedlichen Perspektiven betrachtet werden, ohne dass man neue komplizierte Abfragen definieren und ausführen lassen müsste. Dabei sind die Daten bereits strukturiert und teilweise mit Berechnungslogik versehen.

Ein weiterer wichtiger Aspekt ist die Planung. Da natürlich auch Zellwerte geschrieben werden können, lassen sich auf oberster Ebene Planszenarien erstellen und validieren. Die Verarbeitung von neuen Eingaben kann bei einigen Systemen auch mit Verarbeitungslogik versehen werden, um wiederkehrende oder bekannte Mechanismen zu automatisieren und somit eine bestimmtes Maß an Planungsintelligenz zu hinterlegen. Ein Beispiel ist die Eingabe eines Wertes für das ganze Jahr, der auf die Monate verteilt werden muss. Dies kann gleichmäßig geschehen, aber auch nach anderen Kriterien, etwa saisonbezogen oder abhängig von anderen Werten.

Palo

OLAP-Produkte sind sowohl von etablierten Anbietern (SAP, Oracle, Microsoft) als auch von weniger bekannten Softwareherstellern erhältlich. Der Markt ist aber noch relativ inhomogen, und die Preise sind hoch. Hier setzt Palo an, das als Open-Source-Produkt einen MOLAP-Server kostenfrei unter einer GPL-Lizenz anbietet. Palo wird von der Jedox GmbH aus Freiburg zur Verfügung gestellt, und Binaries wie Sourcecode können unter www.palo.net heruntergeladen werden. Darauf aufsetzend bietet Tensegrity kostenfrei ein Java-API (www.jpalo.net) an, das den Zugriff auf den Server ermöglicht. Im Folgenden stellen wir kurz das API vor und zeigen die Nutzung des API anhand eines kleinen Browsers. Voraussetzung für das Ablaufen des Beispiels ist die Installation des Servers und des APIs. Der Beispiel-Code ist auf der JPalo-Website verfügbar.

Das Java-API von Palo

In der aktuellen Fassung des Palo-Java-API sind sämtliche wichtigen Klassen in einem einzigen Paket, nämlich org.palo.api, untergebracht. Darin befinden sich alle Klassen und Interfaces, die den Zugriff auf die OLAP-Datenbank-Objekte in Java abbilden. Zu den zentralen Schnittstellen gehören u.a.:

  • Connection
  • Database
  • Dimension
  • Element
  • Cube

Das stark vereinfachte UML-Diagramm in Abbildung 2 veranschaulicht die Beziehung dieser Klassen untereinander.

Abb. 2: Die zentralen Klassen des Palo-Java-API
Connection

Das Interface Connection ermöglicht die Verbindung und damit die eigentliche Interaktion mit dem Palo-Server. Mithilfe einer Connection-Instanz lassen sich sowohl die aktuellen Datenbanken des Palo-Servers auslesen als auch neue Datenbanken hinzufügen und nicht mehr benötigte löschen. Über sämtliche Änderungen informieren ConnectionEvents. Um diese zu empfangen, muss an einer Connection ein ConnectionListener registriert werden. Eine Instanz einer Connection erhält man über eine ConnectionFactory:

connection = connectionFactory.getInstance().newConnection(server, port, user, pass);

server, port, user und pass sind String-Parameter, die zur Authentifizierung notwendig sind. Bei der Standard-Clientinstallation kann man mit „localhost““, „1234“, „user“ und „pass“ die Demo-Datenbank ansprechen. Diese Parameter entsprechen den Einstellungen der config.xml und der auth.xml und lassen sich nach eigenem Belieben anpassen, falls z.B. der Server auf einem anderen System installiert wird. Zu finden sind diese Dateien im Installationsverzeichnis des Palo-Servers, auf einem Windows-System z.B. unter C:ProgrammeJedoxPalo Serverdata. Bei erfolgreicher Verbindung lassen sich die gespeicherten Datenbanken mittels Database[] databases = connection.getDatabases(); auslesen. Das Anlegen neuer bzw. das Löschen alter, nicht mehr benötigter Datenbanken, gestaltet sich ähnlich einfach. Beispielsweise erzeugt folgende Zeile eine neue Datenbank:

Database newDb = connection.addDatabase("Name der neuen Datenbank");

Dies verdeutlicht zugleich eine grundlegende Design-Technik, wie sie auch für die anderen Palo-Komponenten gilt, nämlich dass Database, Dimension, Element und Cube immer über die entsprechenden add_-Methoden erzeugt werden. Der dabei festzulegende Name muss im jeweiligen Sichtbarkeitsbereich des Behälters eindeutig sein. Das bedeutet, dass innerhalb einer Connection jede Datenbank einen eindeutigen Namen hat – genauso wie die Namen von Dimensionen und Würfel innerhalb einer Datenbank. Dasselbe gilt für die Elemente einer Dimension.

Database

Im Wesentlichen ist eine Datenbank nichts anderes als ein Behälter für Dimensionen und Würfel. Dementsprechend stellt das Interface Database mehrere Methoden bereit, mit denen sich Informationen über vorhandene Dimensions und Cubes auslesen lassen. Um beispielsweise alle in einer Datenbank gespeicherten Dimensionen zu erhalten, reicht folgende Zeile:

Dimension[] dim = database.getDimensions();

Aber nicht nur das Auslesen von Dimensionen und Würfeln ist möglich, sondern auch das Hinzufügen und Löschen. Hierzu stehen entsprechende addDimension()– und removeDimension()-, sowie addCube()– und removeCube()-Methoden zur Verfügung, deren Aufruf analog der Connection#addDatabase() bzw. Connection#removeDatabase() erfolgt:

Dimension newDim = database.addDimension("Name der neuen Dimension");
Dimension

Dimensionen bilden das Grundgerüst, aus denen sich ein OLAP-Würfel zusammensetzt. Es ist dabei durchaus erlaubt, dieselbe Dimension in verschiedenen Würfeln einer Datenbank zu verwenden. Bausteine einer Dimension sind die so genannten Elemente, die durch das Interface Element repräsentiert werden. Auch das Interface Dimension enthält eine addElement()-Methode, um ein neues Element anzulegen, und eine removeElement()-Methode, um ein Element zu löschen. Daneben finden sich noch weitere Methoden, um Elemente gezielt auszulesen. Eine häufig benötigte Eigenschaft ist z.B. die Abfrage der Elemente in der Reihenfolge, die durch ihre Konsolidierungshierarchie (s.u.) bestimmt ist: Element[] elements = dimension.getElementsInOrder();.

Element

Die Basis einer Dimension bilden Elemente, die durch das Interface Element definiert werden. Die Eigenschaft eines Elements wird durch seinen Typ bestimmt. Momentan unterstützt das Interface die Elementtypen numeric, string und consolidated. Letzteres bezeichnet die Besonderheit, dass ein Element andere Elemente gruppieren kann. Besteht ein Element aus anderen Elementen, so spricht man von Konsolidierung. Solch ein Element hat den Typ consolidated. Mit der Methode getConsolidations() kann man für jedes Element abfragen, welchen Konsolidierungen es angehört:

Conoslidation[] consolidations = element.getConsolidations();
Cube

Ein OLAP-Würfel wird durch das Cube-Interface repräsentiert. Wie bereits erwähnt, besteht ein Würfel aus zwei oder mehr Dimensionen. Das Anlegen eines neuen Würfels erfolgt mithilfe der addCube()-Methode einer Database-Instanz. Hierzu müssen die Dimensionen des Würfels als Array übergeben werden:

Cube newCube = database.addCube("Name des Würfels", dimArray);

Nur über die Cube-Instanz lassen sich Daten speichern und abfragen. Dazu existieren die Methoden setData() und getData(). Beide benötigen als Parameter die Koordinaten des Zellinhalts, der abgefragt werden soll, also einen Elementnamen jeder Dimension, die der Würfel besitzt. Dabei ist die richtige Reihenfolge der Dimension, die beim Anlegen des Cubes festgelegt wird, wichtig. Im nachfolgenden Beispiel wird das Auslesen von Daten aus einem Würfel anschaulich erklärt.

Palo-Browser-Beispiel

Nachdem die wichtigsten Datenbank-Objekte nun bekannt sind, zeigt jetzt eine einfache Beispielanwendung die Verwendung des Palo-Java-API. Die dabei erstellte Anwendung ermöglicht es, durch die im Palo-Server gespeicherten Datenbanken und die darin enthaltenen Würfel und Dimensionen zu navigieren und eine einfache Tabellenansicht der Werte eines Würfels zu erhalten. Diese Werte werden in einem Baum, einer Art Explorer-Ansicht, dargestellt. Sie können in dem Beispiel anhand zweidimensionaler Tabellen angezeigt werden. Da der Würfel aber mehr als zwei Dimension enthalten kann, müssen die Koordinaten der nicht dargestellten Dimensionen eindeutig festgelegt werden. Um z.B. einen dreidimensionalen Würfel anzuzeigen, muss man einen zweidimensionalen Ausschnitt wählen. Dazu legt man zwei Dimensionen fest, deren Felder in der Tabelle angezeigt werden, und das Feld der dritten Dimension bestimmt man als statisch. Dies nennt man im OLAP-Jargon auch Schnitt (Slice).

Bei der Neuinstallation wird eine Demo-Datenbank mitinstalliert, auf die das Beispiel direkt zugreifen kann. Zunächst muss eine Verbindung zum Palo-Server hergestellt werden. Im Beispielprogramm werden die Verbindungsdaten über einen Dialog abgefragt (Abb. 3).

Abb. 3: Einlesen der Verbindungsdaten

Anschließend wird der Verbindungsaufbau gestartet:

public final void connect(String server, String service, String user, String pass)
       throws PaloBrowserException 
{
       connection = ConnectionFactory.getInstance().newConnection(
       server, service, user, pass);
       if(connection == null)
           throw new PaloBrowserException("Failed to connect to"+server);
       //fill explorer tree:
       updateTree();

Sollte dies aus irgendeinem Grund fehlschlagen, werden eine PaloBrowserException geworfen und eine entsprechende Rückmeldung an den Benutzer geliefert. War der Verbindungsaufbau jedoch erfolgreich, wird die zurückgelieferte Connection-Instanz benutzt, um den Inhalt des Palo-Servers als Baumstruktur darzustellen.

Beispielhaft zeigt der folgende Code, wie eine Jtree-Komponente gefüllt wird. Dies geschieht in der update(DefaultMutableTreeNode node) -Methode, die rekursiv die Baumstruktur erstellt. Handelt es sich beim übergebenen Knoten um das Wurzelelement, werden zunächst alle darunter liegenden Einträge entfernt. Anschließend werden alle vorhandenen Datenbanken mithilfe der aktuellen Verbindung über browser.getConnection().getDatabases() ausgelesen. Jede Datenbank wird in einem Knoten als so genanntes userObject gespeichert und dem Baum hinzugefügt. Generell werden die userObjects der Knoten verwendet, um Referenzen auf die jeweiligen Palo-Bestandteile zu speichern. Schließlich wird die update()-Methode mit diesem Knoten erneut aufgerufen. Analog ist das Vorgehen bei Dimensionen, Würfeln und Elementen.

public class PaloBrowserTree extends JTree 
{
       PaloBrowser browser; //zentrale Klasse, die eine Connection Instanz hält
       //weitere Deklarationen, z.B. die eines standard tree models
       ...
v//Konstruktor
       public PaloBrowserTree(PaloBrowser browser) 
       {
              this.browser = browser;
              ...
       }

       public void update() 
       {
              DefaultMutableTreeNode root = 
                      (DefaultMutableTreeNode)model.getRoot();
              if(browser.isConnected()) 
              {
              //is connected:
                     update(root);
              } else
              ...
       }

       private final void update(DefaultMutableTreeNode node) 
       
              //die palo eigenschaften sind im user object des knoten gespeichert
              Object uo = node.getUserObject();
              //check user object:
              if (node == this.model.getRoot()) 
              {
                     DefaultMutableTreeNode root = node;
                     String desc = browser.getConnection().getServer() + "/"
                            + browser.getConnection().getService();

                     root.setUserObject(desc);
                     removeChildren(root);
                     Database databases[] = browser.getConnection().getDatabases();
                     for (int i = 0; i 

Während das Auslesen noch recht einfach war, gestaltet sich die Abfrage der eigentlichen Daten schon etwas komplizierter. Wie bereits im Abschnitt Cube erwähnt, müssen bei Anfragen immer sämtliche Dimensionen eines Würfels angegeben werden – und dies in der richtigen Reihenfolge. Besteht beispielsweise ein Cube aus den Dimensionen A, B und C mit jeweils nur einem Element, dann erhält man den Wert an der Stelle [El(A), El(B), El(C)] durch folgende Abfrage:

Object value = cube.getData(new Element[]{elA, elB, elC});

Man sieht, dass ein Array von Elementen der jeweiligen Dimensionen die Koordinate festlegt. Im Beispielprogramm werden die Daten eines Cube in einer einfachen Tabelle visualisiert, d.h., es werden immer nur zwei Dimensionen eines Würfels angezeigt. Das Ermitteln der richtigen Werte übernimmt hierbei eine Implementierung des TableModel (siehe folgenden Quellcode). Der Konstruktor benötigt neben dem aktuellen Cube vor allem die Dimensionen, die in den Zeilen und den Spalten dargestellt werden sollen. Die eigentliche Abfrage der Daten pro Zelle erfolgt in der getValueAt(int rowIndex, int columnIndex) -Methode. Die erste Spalte der Tabelle ist dabei für die Elementnamen reserviert, die gegebenenfalls zurückgeliefert werden. Andernfalls wird die Abfrage zusammengebaut. Als Erstes werden die gewünschten Elemente der jeweiligen Spalten- und Zeilendimension bestimmt. Anschließend werden die Dimensionen des Würfels durchlaufen. Um das Beispiel einfach zu halten, werden für die nicht angezeigten Dimensionen immer ihre ersten Elemente für die Abfrage verwendet. Bei den Dimensionen der Tabelle werden natürlich die gewünschten Elemente eingesetzt. Schließlich wird die Anfrage an die Cube-Instanz weitergereicht und der aktuelle Wert zurückgeliefert.

public class PaloTableModel extends AbstractTableModel 
{
       //Konstruktor
       public PaloTableModel(PaloBrowserTable paloTable, Cube cube,Dimension row, 
                     Dimension col) 
       {
              ...
       }

       public int getRowCount() 
       {
              return row == null ? 0 : row.getElementCount();
       }

       public int getColumnCount() 
       {
              //+1, da 0te spalte für element namen reserviert
              return col == null? 0 : col.getElementCount() + 1; 
       }

       public Object getValueAt(int rowIndex, int columnIndex) 
       {
              //die erste spalte zeigt den jeweiligen element namen an
              if (columnIndex == 0) 
                     return row.getElementAt(rowIndex).getName();
              //anpassen des column index, da intern anders verwaltet
              columnIndex = columnIndex-1; 
              //erstellen der Abfrage:
              Element rowEl = row.getElementAt(rowIndex); //gewünschtes Zeilen-El. 
              Element colEl = col.getElementAt(columnIndex); //gew. Spalten-El.
              int dimCount = cube.getDimensionCount();
              Element[] query = new Element[dimCount]; //Abfrage mit allen Dims. 
              for (int I = 0; I 

Soweit wollen wir es bei diesem Beispiel belassen. Einen Eindruck, wie das fertige Programm aussieht, vermittelt Abbildung 4. Den Quellcode kann man unter www.jpalo.net herunterladen. Nächste Schritte zur Erweiterung des Beispiels wären die Möglichkeit, die Konsolidierungshierarchien in der Tabelle anzuzeigen oder das jeweils ausgewählte Element der nicht angezeigten Dimension anzuzeigen bzw. in einer Auswahlliste veränderbar zu machen, um sich innerhalb des Datenraums des Würfels bewegen zu können.

Abb. 4: Ein einfacher Browser zum Anzeigen von Palo-Daten
Tensegrity

Die Tensegrity Software GmbH aus Köln stellt das hier vorgestellte Java-API und einen Eclipse-RCP-Client kostenlos zur Verfügung. Der Palo-Eclipse-Client erlaubt die komfortable Administration von Palo-Datenbanken und die Definition von Views auf Palo Cubes. Beides kann man unter www.jpalo.net kostenlos herunterladen.
Tensegrity konzentriert sich auf die Visualisierung und Modellierung von betriebswirtschaftlichen Daten und hat sich als Spezialist für die Implementierung von SWT-basierten Anwendungen mithilfe des Eclipse-Frameworks etabliert.

Der Nutzen

Das Beispiel hat gezeigt, dass die Benutzung des Palo-Java-APIs sehr einfach ist. Schon in kürzester Zeit kann man damit kleine Programme erstellen. Sowohl dieses Beispiel als auch die in diesem Artikel vermittelten Grundlagen sollten eine Anregung sein, um eigene OLAP-basierte Anwendungen mit dem Palo-Java-API zu entwickeln.

Ein wichtiger weiterführender Aspekt ist natürlich die Übertragung und Verdichtung von Daten aus relationalen Systemen in multidimensionale Systeme. Dabei werden die Dimensionen und Cubes aus Informationen der relationalen Tabellen erzeugt. Dies wäre allerdings ein eigenes Thema, das den Rahmen dieses Artikels sprengt.

Michael Raue ist Geschäftsführer, Mitgründer und Miteigentümer der Tensegrity Software GmbH.
Geschrieben von
Michael Raue
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.