Kartendarstellung mit Pentaho Community Dashboards

(English version)

Im Pentaho BI Server ist eine sehr flexible Karten-Komponente enthalten, die leider nicht gerade ausführlich dokumentiert ist. Ich möchte hier eine kurze Anleitung für einen erfolgreichen Start geben.

Zuerst braucht man Positionsdaten. Diese liegen entweder als echte Geodaten (z. B. aus einer GIS-Datenbank wie PostGIS) oder als Breiten- und Längengrad (latitude/longitude) vor. Im Dashboard brauchen wir die lat/lon-Darstellung.

Als erstes legen wir im Layout-Panel des Dashboard-Editors einen Bereich für die Karte an, z. B. eine Zeile und darin eine Spalte, in diesem Beispiel mit einer Breite von 10 Elementen (Medium Devices). Diese Spalte benennen wir so, daß die Verbindung zum Map-Element erkennbar ist, z. B. MapDiv.

Datenquelle

Die Datenquelle für die Punkte auf der Karte definieren wir im Datasources Panel. Hier legen wir eine Abfrage namens MapQuery an, die uns die Geokoordinaten liefert. Diese Spalten müssen „Latitude“ und „Longitude“ heißen (die Klein- oder Großschreibung ist egal).

Hat man echte Geodaten in einer GIS-fähigen Datenbank, sind die Punkte eventuell in einer eigenen Spalte zusammengesetzt gespeichert. Das läßt sich leicht in die benötigten Koordinaten aufspalten:


SELECT ST_X(ST_Transform(geo, 4326)) as longitude,
       ST_Y(ST_Transform(geo, 4326)) as latitude
FROM gis_table

In diesem Beispiel ist „geo“ der Name der Geodaten-Spalte. Mit ST_Transform(geo, 4326) konvertiert PostGIS die Koordinaten aus der in der Datenbank verwendeten Projektion in Länge- und Breitengrad. ST_X und ST_Y extrahieren aus dem konvertierten Objekt die einzelnen Koordinaten.

Karten-Komponente

Jetzt kann das Karten-Element im Components Panel angelegt werden: Custom: NewMapComponent.

Als Name wählen wir in diesem Beispiel einfach „Map“. Als Datasource tragen wir den Namen der Datenquelle (MapQuery) ein, und als HtmlObject den Namen des angelegten Bereichs (MapDiv).

Wenn wir das Dashboard speichern und ausführen, stellen wir fest, daß keine Karte angezeigt wird. Das liegt daran, daß die Karten im Gegensatz zu anderen Elementen selbst keinen Platz beanspruchen. Wir müssen also Breite und Höhe des enthaltenden Elements festlegen, entweder im Layout Panel mit Height, oder in einem Stylesheet.

Das Ergebnis der Mühen ist eine Karte, in der die Punkte aus der Datenbankabfrage mit farbigen Standard-Symbolen markiert sind.

Büchereien in Wien - Kartendaten (c) OpenStreetMap contributors
Büchereien in Wien – Kartendaten (c) OpenStreetMap contributors

Standardmäßig zeigt die Karte die ganze Erde an. Meist will man aber eine kleinere Region anzeigen. Das geht mit den Optionen Center Latitude und Center Longitude sowie Default Zoom Level.

Die beiden Center-Koordinaten kann man von der Karte ablesen, wenn man mit der Maus über sie fährt. Der Zoom Level hängt von der Größe der Kartendarstellung und dem darzustellenden Gebiet ab. Für eine Großstadt kann der Zoom ca. 12 betragen, Österreich paßt bei Zoom 7 ganz gut, Deutschland braucht schon Zoom 6.

Anpassung der Marker

Die Standard-Markierungen der Punkte auf der Karte passen nicht zu jeder Anwendung. Es besteht die Möglichkeit, eigene Symbole anzuzeigen: dazu gibt man in der Datenquelle die URL zum Symbol (ganz normale Bilddatei) in der Spalte „marker“ aus. Damit lassen sich zum Beispiel unterschiedliche Zustände der dargestellten Objekte anzeigen.

Popups

Zu jedem Marker können wir Zusatzinformationen anzeigen lassen. Wenn die Datenquelle eine Spalte „popupContents“ enthält, wird deren Inhalt (optional HTML-formatiert)  angezeigt, wenn der Benutzer ein Marker-Symbol anklickt. Mit Popup Width und Popup Height läßt sich die Größe des Popups an den erwarteten Inhalt anpassen.

Beispiel eines formatierten Popups - Kartendaten (c) OpenStreetMap contributors
Beispiel eines formatierten Popups – Kartendaten (c) OpenStreetMap contributors

Mit diesen Optionen läßt sich schon ganz ohne Programmierung viel machen. Mit etwas JavaScript läßt sich noch viel mehr erreichen.

Automatische Aktualisierung der Karteninhalte

Im Gegensatz zu vielen anderen Dashboard-Komponenten bietet NewMapComponent keine Funktion zum automatischen Aktualisieren des Inhalts in festgelegten Abständen. In einigen Fällen möchte man jedoch die Positionen beweglicher Objekte darstellen und die Karte von Zeit zu Zeit automatisch aktualisieren. Glücklicherweise läßt sich das mit ein wenig JavaScript-Code erreichen.

In den Advanced Properties der Karten-Komponente geben wir in der Eigenschaft Post Execution eine Funktion ein:


//Sets up a timer to refresh the map after a minute
function () {
    this.timerId = window.setTimeout(
        function() {
            render_Map.update();
        }
    , 60000);
}

60000 ist die Anzahl der Millisekunden, nach denen der Timer laufen soll. render_Map ist der Name der Karten-Komponente, mit „render_“ davor – so benennt das Community Dashboard Framework das JavaScript-Objekt.

Da diese Funktion immer nach dem Aktualisieren der Karte ausgeführt wird, ist gleich der nächste Timer nach der gleichen Periode aktiviert. Die Timer-ID, die in JavaScript zum Abbrechen des Timer genutzt werden kann, wird dabei im render_Map-Objekt gespeichert.

Es gibt nur ein Problem: Verschiebt der Benutzer den Kartenausschnitt oder zoomt hinein oder hinaus, setzt die Aktualisierung der Karte den Ausschnitt und den Zoom-Wert auf die Standardwerte. Die Karte kehrt also zum Ausgangspunkt zurück. Um das zu vermeiden, können wir vor dem Update noch schnell die aktuelle Sicht abspeichern, wodurch die Karte nicht mehr springt.

Folgende Funktion gehört in die Pre Execution-Eigenschaft:

//Before reloading the map automatically, save the current zoom level and position
function () {
    if (this.timerId != null) {

        //Get current map center and zoom level
        center = this.mapEngine.map.center;
        zoom = this.mapEngine.map.zoom;

        //Transform to WGS84 coordinates
        center.transform(this.mapEngine.map.projection, "EPSG:4326");

        this.defaultZoomLevel = zoom;
        this.centerLongitude = center.lon;
        this.centerLatitude = center.lat;
    }
}

Zuerst überprüfen wir, ob die timerId schon gesetzt ist. Beim ersten Anzeigen der Karte (wenn das Dashboards geöffnet wird) ist das noch nicht der Fall.

Ist die Karte schon fertig dargestellt worden, ist timerId beim nächsten Durchlauf nicht mehr leer, dann können wir also die Position und den Zoom-Level der Karte abfragen und in die Standardeinstellung der Komponente hineinschreiben.

Bei der nächsten automatischen Aktualisierung der Karte tritt zwar ein systembedingtes Flackern auf, aber der vom Benutzer gewählte Bildausschnitt bleibt bestehen.

Die Map-Komponente bietet noch andere Möglichkeiten, so wie das Thema der GIS-Daten ein fast unerschöpfliches ist. Ich werde sicher noch weitere Beiträge in diesem Themenkreis schreiben.

Displaying maps with the Pentaho Dashboard Framework

Pentaho BI Server contains a map component that’s very versatile but unfortunately quite sparsely documented. I’d like to give you a simple introduction into using the component.

First, we need position data. These are either stored in a real geographic database like PostGIS or separated into latitude and longitude. The dashboard map needs the lat/lon form.

First we create an area for the map in the Layout Panel of the Dashboard Editor. This can be a row and a column in it, for example with a width of 10 elements (enter it in the Medium Devices setting). We name this column MapDiv to state that it belongs to the map.

Data source

We need to specify the data source of the points in the Datasources Panel. Here, we enter a query called MapQuery that returns the coordinates. The columns must be called „Latitude“ and „Longitude“ (capitalization doesn’t matter).

Geograpic data in a GIS-capable database stores the points in a single column. It is easy to separate the two coordinates:


SELECT ST_X(ST_Transform(geo, 4326)) as longitude,
       ST_Y(ST_Transform(geo, 4326)) as latitude
FROM gis_table

In this example, „geo“ is the name of the geodata column. In PostGIS, ST_Transform(geo, 4326) converts the coordinates from the geographic reference system used in the database to the classic Earth latitude and longitude values. ST_X and ST_Y extract the longitude and latitude from the compound object.

Map component

Now we create the Map element in the Components Panel by adding a Custom: NewMapComponent.

The name is simply „Map“ in this example. The Datasource is the name of our data source (MapQuery) and the HtmlObject is the name of the created row (MapDiv).

After saving and executing the dashboard, no map is shown. The reason is that the Map component itself doesn’t specify a content height, as other components do. So we need to set the width and height ourselves, either in the Layout Panel (Row Height) or in a stylesheet.

The result is a map that visualizes points from the database query with standard symbols in different colors.

By default, the map shows the entire Earth. We usually want to restrict the displayed area: this is done with the options Center Latitude/Longitude and Default Zoom Level.

The Center coordinates are displayed on the map when moving the mouse over it. The zoom level depends on the size of the map and the area to be shown. For a large city, the zoom can be around 12, Austria fits well with zoom = 7, and Germany requires zoom = 6.

Changing the markers

The default markers of map points aren’t suitable for some requirements. It is possible to use our own symbols: just return the URL of the symbol (a normal image file) in the column called „marker“ in the map data source. This allows us to visualize different object states.

Popups

For each marker we can display additional information in a popup area. If the data source contains a column named „popupContents“, its text (optionally HTML formatted) is displayed when the user clicks on a marker symbol. Popup Width and Popup Height can be changed to match the size of the content to display.

Using these options, we can already do a lot, entirely without programming. A bit of JavaScript can do a lot more.

Periodic updates of the map contents

In contrast to many other dashboard components, the NewMapComponent doesn’t have a setting for periodic updates. Sometimes we have to visualize objects that can move and automatically refresh the map from time to time. Fortunately, only a few lines of simple JavaScript are necessary to achieve this.

We enter the following function in the Advanced Properties of the Map component, in the property Post Execution:


//Sets up a timer to refresh the map after a minute
function () {
    this.timerId = window.setTimeout(
        function() {
            render_Map.update();
        }
    , 60000);
}

60000 is the number of milliseconds after the timer executes the function. The map component is named render_Map in this example: the Community Dashboard Framework always prefixes the specified names with „render_“ to create the JavaScript object in the running dashboard.

This function is executed after each update of the map, so it also sets up the next automatic update after the same period. The timer ID stored in the render_Map object could be used to cancel the timer if desired.

However, there’s one usability problem: If the user moves the map or zooms in, the automatic update resets the map to the values defined in the dashboard properties and the map returns to the initial view. We can avoid this by storing the properties of the current view before the map update, so the map doesn’t jump around anymore.

The following function is entered into the Pre Execution property:

//Before reloading the map automatically, save the current zoom level and position
function () {
    if (this.timerId != null) {

        //Get current map center and zoom level
        center = this.mapEngine.map.center;
        zoom = this.mapEngine.map.zoom;

        //Transform to WGS84 coordinates
        center.transform(this.mapEngine.map.projection, "EPSG:4326");

        this.defaultZoomLevel = zoom;
        this.centerLongitude = center.lon;
        this.centerLatitude = center.lat;
    }
}

The function checks if the timerId is set. If the map is displayed the first time (when opening the dashboard), this is not yet the case.

In a map that is already displayed, the timerId has a value, so we can store the map’s position and zoom level in the properties of the map object.

The map update causes a visible flicker of the dashboard, but at least the map area selected by the user stays as it is.

The map component offers a lot more, and GIS data is an almost infinite topic. This blog post isn’t the last one about maps, that’s for sure.

Update-Strategie beim Pentaho BI Server

Ein- bis zweimal im Jahr erscheint eine neue Version der Pentaho-Software mit sinnvollen Neuigkeiten, die man gerne auf den eigenen Servern anwenden möchte. Die Art des Releases (Programm, Daten und Konfiguration gemischt) ist zwar für einen schnellen Start mit der Software gut geeignet, aber ein Update auf die neue Version kann schwierig sein, wenn man die Konfiguration am Anfang nicht sauber herausgetrennt hat.

Mein Ansatz dazu ist folgender:

Im Hauptverzeichnis (z. B. /opt/pentaho) liegen die Verzeichnisse des Servers mit Versionierung (z. B. biserver-ce-5.3). Zusätzlich die Verzeichnisse configuration, repository und jdbc.

Die aktuell in Produktion verwendete Version wird ohne Versionsnummer (biserver-ce) verlinkt. Somit verweist der Startskript immer auf den richtigen Server, und bei Problemen mit einer neuen Version könnte man leicht zur älteren zurückkehren.

Diese Lösung erleichtert den Umstieg auf eine neue Version und verringert die Backup-Datenmenge (von 600 MB auf einige KB), weil die biserver-ce-Verzeichnisse nicht mitgesichert werden müssen, da nichts an eigener Arbeit in ihnen liegt.

Repository

Die aktuellen Releases des BI-Servers verwenden ein Jackrabbit-File-Repository in biserver-ce/pentaho-solutions/system/jackrabbit. Hierin liegt die Konfigurationsdatei sowie das Verzeichnis „repository“, das ich wie beschrieben ins Pentaho-Verzeichnis (raus aus der biserver-ce-Verzeichnisstruktur) verschiebe und mit einem Symlink verlinke. Vor einem Update auf eine neue Pentaho-Version sollte man dieses Verzeichnis zusätzlich sichern, da eine neuere Jackrabbit-Version ein neues Format einführen könnte, das mit älteren Versionen inkompatibel ist.

Datenbankkonfiguration

Die Konfiguration besteht aus folgenden Dateien:

pentaho-solutions/system/hibernate/hibernate.conf
pentaho-solutions/system/hibernate/gewählteDatenbank.conf
tomcat/webapps/pentaho/META-INF/context.xml

Zusätzlich deaktiviere ich in tomcat/webapps/pentaho/WEB-INF/web.xml den Start der hibernate- und quartz-Datenbanken mit HSQLDB. Die Sampledata-Datenbank wird von mitgelieferten Komponenten des Servers benötigt und bleibt daher aktiviert, in der vom Server mitgelieferten Version.

Diese vier Konfigurationsdateien gehören auch ins herausgelöste Konfigurationsverzeichnis verschoben und aus dem Server verlinkt. Die Dateien in pentaho-solutions können auch mit Symlinks verbunden werden, jene in Tomcat müssen aber Hardlinks sein.

Anpassung des Login-Fensters

Im Produktivbetrieb hat man die Default-Paßwörter geändert und die mitgelieferten User deaktiviert oder gelöscht. Deswegen ist die standardmäßig eingeschaltete Möglichkeit, als User oder Admin mit einem voreingestellten Paßwort einzuloggen, nicht mehr notwendig.

Das läßt sich in pentaho-solutions/system/pentaho.xml abschalten (login-show-users-list, login-show-sample-users).

Zusätzlich kann man das Login-Fenster mit Änderungen am mitgelieferten Stylesheet (pentaho-solutions/system/common-ui/resources/themes/crystal/globalCrystal.css) an die eigenen Vorstellungen anpassen.

Update strategy for Pentaho BI Server

Pentaho releases one or two new versions of their open source software each year, with interesting new functionality or bugfixes. The way the release is done is well suited for a new evaluation installation, but updating to the new version can be difficult if one didn’t separate out the configuration after the setup.

This is my approach to solving the issue:

There’s a main directory (e.g. /opt/pentaho). In it, the BI server’s files are unzipped and versioned (e. g. biserver-ce-5.3). In addition to the server directories, there’s also configuration, repository and jdbc.

The current production version is symlinked without a version number (e. g. biserver-ce). This causes the start script to always point to the correct server, but switching versions is still easy if necessary.

With this solution, it’s much easier to update to a new version. Backups are much smaller, only the few kilobytes of the configuration instead of the whole BI server (600 MB).

Repository

Current releases of Pentaho BI Server use a Jackrabbit file repository which is in biserver-ce/pentaho-solutions/system/jackrabbit. In this directory there’s a configuration file and a „repository“ directory which gets moved into the main Pentaho directory (out of the biserver-ce structure) and symlinked in „jackrabbit“. It’s a good idea to backup this directory before updating to a new release as Jackrabbit could possibly update the format so that it’s not compatible with older Pentaho releases anymore.

Database configuration

If you changed your database configuration from HSQLDB to another database, the following files are to be moved into configuration:

pentaho-solutions/system/hibernate/hibernate.conf
pentaho-solutions/system/hibernate/yourDatabaseSystem.conf
tomcat/webapps/pentaho/META-INF/context.xml

In addition, in tomcat/webapps/pentaho/WEB-INF/web.xml I deactivated the hibernate and quartz HSQL databases. The sampledata database is required by some components of the server, so I keep it active.

When moving these files into the separate config directory, be careful when linking. Tomcat doesn’t like symlinks so they need to be hardlinked.

Changing the login screen

On a production system the default passwords are hopefully changed and the sample users are deactivated or removed. So the default mechanism for logging as user or Admin in with predefined passwords is not necessary anymore.

This can be switched off in pentaho-solutions/system/pentaho.xml (login-show-users-list, login-show-sample-users).

In addition, the login screen can be further customized by changing the stylesheet (pentaho-solutions/system/common-ui/resources/themes/crystal/globalCrystal.css) for your own requirements.