RapidMiner Custom Operator tutorials

(English)

Die neue Custom-Operator-Erweiterung in RapidMiner beschäftigt mich weiter.

In den letzten Tagen habe ich zwei detaillierte Anleitungen in die RapidMiner-Community gestellt, um anderen die Entwicklung eigener Operatoren sowie die Arbeit mit der GeoProcessing-Extension zu vereinfachen:

Tutorial for creating custom operators

Tutorial for the GeoProcessing extension

RapidMiner Custom Operator Tutorials

The mesmerizing Custom Operators extension in RapidMiner is keeping me busy.

I put two detailed tutorials into the RapidMiner Community in order to make it easier for others to create their own operators and to start analyzing data with the GeoProcessing extension:

Tutorial for creating custom operators

Tutorial for the GeoProcessing extension

Custom Operators in RapidMiner

(English)

Bei der RapidMiner-Wisdom-Konferenz im Februar 2020 wurde eine revolutionäre neue Erweiterung vorgestellt: Custom Operators. Mit Hilfe dieser Extension, die bereits im Marketplace verfügbar ist, können RapidMiner-Prozesse in Operatoren umgewandelt werden, die man dann zu Erweiterungen zusammenfassen kann.

Als langjähriger RapidMiner-Benutzer habe ich viele wiederverwendbare Prozesse erstellt und auch hier vorgestellt. Es war nur bisher nicht so leicht, diese Ergebnisse mit anderen zu teilen und vor allem im RapidMiner-Ökosystem sichtbar zu machen. Mit Hilfe der neuen Erweiterung ist genau das möglich: die erstellten Erweiterungen sind für die Aufnahme ins RapidMiner Marketplace geeignet, und sind bereits dort verfügbar.

Die Erweiterungen sind:

  • Database Envy: Aktuell zwei Operatoren, die hilfreiche Funktionalität aus SQL-Datenbanken nachbilden: Window Functions und Expression-based Join. Beides habe ich früher bereits im Blog vorgestellt, jetzt sind sie leicht in RapidMiner Studio installierbar und benutzbar.
  • GeoProcessing: Diese Erweiterung basiert auf meiner Blog-Serie zu GIS in RapidMiner. Derzeit 8 Operatoren decken viele Aufgaben im Bereich GIS-Verarbeitung ab. Die bisher aufwändige Installation der GeoScript-Bibliotheken entfällt, da diese in der Erweiterung bereits enthalten sind. RapidMiner-Prozesse können damit Daten aus Shapefiles lesen, Koordinatensysteme projizieren, Kennzahlen wie Ausdehnung, Distanz und Fläche berechnen, Geometrien transformieren und vieles mehr.
  • JSON Processing with jq: Auch dieses Thema habe ich bereits vorgestellt. Mit Hilfe von jq-Ausdrücken können RapidMiner-Prozesse jetzt komplexe Umformungen an JSON-Dokumenten durchführen, oder Teile von ihnen extrahieren. Das ermöglicht die Verarbeitung der Ausgabe mancher Web-APIs, die mit den bisherigen Mitteln in RapidMiner nicht oder nur sehr schwer zu verarbeiten waren.

Detailinformationen zu den Erweiterungen und ihrem Status sind auf der Extension-Homepage zu lesen.

Ich erwarte viele neue spannende Erweiterungen im Marketplace in naher Zukunft, da jetzt ganz neue Gruppen (Data Scientists, die mit RapidMiner arbeiten, aber nicht programmieren) sie entwickeln und publizieren können.

Custom Operators in RapidMiner

A revolutionary new extension called Custom Operators was presented at the RapidMiner Wisdom Conference in February 2020. This extension (already available in the Marketplace) creates new operators from RapidMiner processes and can bundle them to proper extensions.

In my years of using RapidMiner I created many reusable processes, and often presented them here. However, until now, it wasn’t easy to share these results with others and make them visible in the RapidMiner ecosystem. This is now possible: the newly created extensions can be published in the RapidMiner Marketplace, and they are already available.

The initial set of extensions is:

  • Database Envy: Two operators with functionality similar to SQL databases: Window Functions and Expression-based Join. I published both earlier in my blog; now they are available for installation inside RapidMiner Studio.
  • GeoProcessing: Based on my blog series GIS in RapidMiner. 8 operators solve many tasks in geometry and geography processing. The complex installation of GeoScript libraries is not necessary anymore, as these are bundled with the extension. RapidMiner processes can import data from Shapefiles, reproject coordinate reference systems, calculate measures like area and distance, transform geometries and a lot more.
  • JSON Processing with jq: This is also a topic I wrote about before. RapidMiner processes can now use jq expressions to transform JSON documents or extract parts. This enables the processing of some Web APIs that were hard or impossible to use with RapidMiner before.

The extension homepage contains more details about each module.

I expect many interesting extensions to appear in the Marketplace soon, now that data scientists can develop and publish them so easily.

RapidMiner: Zugriff auf Prozessdefinition

(English)

Ich hatte die Aufgabe, Daten aus einem anderen Prozess im RapidMiner-Repository auszulesen. Interessant war in diesem Fall der konkrete Wert eines Makros im Prozesskontext. Das ist eine Konfigurationseinstellung, die nur dort festgelegt wird, aber auch anderswo nötig ist.

Mit Bordmitteln kommt man nicht weiter: Loop Repository, Retrieve, Open File weigern sich alle, einen Prozess aus dem Repository zu öffnen. Auch in den Extensions „Converters“ und „Operator Toolbox“ gibt es nichts dazu.

Aber wie so oft bei RapidMiner hilft ein kurzes Groovy-Skript, das man im eingebauten „Execute Script“-Operator ausführt.

import com.rapidminer.repository.RepositoryLocation;
import com.rapidminer.RepositoryProcessLocation;

//Aktueller Pfad im Repository
parentLoc = operator.getProcess().getRepositoryLocation().parent();
//Repository-Eintrag relativ zum aktuellen Pfad
loc = new RepositoryLocation(parentLoc, "Example process");
//Der auszulesende Prozess als XML-String
processCode = new RepositoryProcessLocation(loc).getRawXML();

//Den Code als Macro ausgeben
operator.getProcess().getMacroHandler().addMacro("processXML", processCode);

Nach der Ausführung steht dann im Macro „processXML“ der XML-Code des ausgelesenen Prozesses. Daraus können wir dann mit RapidMiner-Bordmitteln die gewünschte Information rausholen.

In diesem Beispiel lesen wir zwei Dinge aus:

  • Den Wert des Makros „exampleMacro“ im Prozesskontext
  • Den Parameter „number_examples“ im Operator „Generate Data“

Mit Create Document und Write Document aus der Text-Processing-Erweiterung können wir den Wert des Makros in ein Document-Objekt umwandeln und in eine Datei schreiben. Das hilft bei der Erfassung der Daten mit dem Read-XML-Wizard, oder bei der Entwicklung der XPath-Ausdrücke mit einem XPath-Tester.

Man findet mit etwas Ausprobieren recht leicht die notwendigen XPath-Ausdrücke. Für den Kontext-Macro:

//context/macros/macro[key/text() = 'exampleMacro']/value

Und für den Parameter des Operators:

//process/operator/process/operator[@name = 'Generate Data']/parameter[@key='number_examples']

Diese Ausdrücke erscheinen etwas komplex, aber wenn man XPath erstmal gelernt hat, doch recht logisch. Natürlich könnte man die richtigen Pfade in Read XML grafisch auswählen, über die Kontext-Makros bzw. Operator-Parameter iterieren, und dann mit Filter Examples die richtigen Daten auslesen. Das ist Geschmackssache. Der ganze Prozess kann so aussehen:

Beispielprozess zum Auslesen der Metadaten eines anderen Prozesses in RapidMiner Studio

Grundsätzlich funktioniert der Prozess auch auf dem Server. Ich hatte bei der Implementierung eines Webservices jedoch eine Eigenart entdeckt: Bei der direkten Ausführung des Prozesses gab es einen Fehler bei der Ermittlung des aktuellen Repository-Pfades. Das konnte ich jedoch umgehen, indem ich diesen Prozess einfach in einen anderen eingebettet und mit Execute Process ausgeführt habe.

Der Beispielprozess kann hier heruntergeladen werden.

Accessing the process definition in RapidMiner

I got a somewhat special task: We needed some data from another RapidMiner process in the repository, namely the value of a process context macro. This macro is a configuration value, it needs to be defined in one place, but is being used in others.

The built in methods don’t help: Loop Repository, Retrieve, Open File all detect the object type and refuse to open the process. The useful extensions Converters and Operator Toolbox also don’t contain anything for this task.

But — as it is so often the case in RapidMiner — a short Groovy script helps. It is executed in an Execute Script operator.

import com.rapidminer.repository.RepositoryLocation;
import com.rapidminer.RepositoryProcessLocation;

//Current repository path
parentLoc = operator.getProcess().getRepositoryLocation().parent();
//Other repository entry, relative to the current path
loc = new RepositoryLocation(parentLoc, "Example process");
//Process to read as XML
processCode = new RepositoryProcessLocation(loc).getRawXML();

//Add a macro with the process XML
operator.getProcess().getMacroHandler().addMacro("processXML", processCode);

After executing this script, the macro „processXML“ contains the other process in its XML representation. Now we can use standard RapidMiner functionality to extract the necessary information.

Here we extract two items from the process definition:

  • The value of the macro „exampleMacro“ in the process context
  • The parameter value for „number_examples“ in the operator „Generate Data“

Create Document and Write Document in the Text Processing extension are being used to create a Document object from the macro value and write it into a file. With this, we can use the wizard in Read XML, and develop XPath expressions in an XPath tester.

With some experimenting we easily find the necessary XPath expressions. To get the context macro with the specified name:

//context/macros/macro[key/text() = 'exampleMacro']/value

And the operator parameter:

//process/operator/process/operator[@name = 'Generate Data']/parameter[@key='number_examples']

These expressions seem to be a bit complex, but it’s really basic XPath. If you prefer to work more code-free, you can select the containing paths in the Read XML wizard and then use Filter Examples to get the data you prefer.
This is how the entire process could look like:

Example process to read metadata from another process in RapidMiner Studio

The same process works on the server. I found a small glitch when implementing it as a web service: When accessing the process directly, it throws an error when trying to determine the current repository path. But this can be easily fixed by calling the process from another using Execute Process.

The example process is available for download here.

Linuxwochen-Vortrag: PostgreSQL ist meine Entwicklungsumgebung

(english)

Dieses Jahr heißt mein Thema bei den Linuxwochen Wien: PostgreSQL ist meine Entwicklungsumgebung. Ich halte den Vortrag am 2. 5. um 12:00 in Raum F0.02. (Mehr Details auf der Linuxwochen-Seite.)

Zusammenfassung:

Die Datenbank als Werkzeugsammlung

Was macht man, wenn man kein Entwickler ist, aber trotzdem einfach und zuverlässig Daten verarbeiten möchte? 
Mit Hilfe von PostgreSQL ist vieles möglich, was nicht zu den Kernaufgaben einer Datenbank gehört, ohne große Programmierkenntnisse. Der Vortrag wird Foreign Data Wrappers und Erweiterungen für PostgreSQL vorstellen und Beispiele für die Lösung praktischer Entwicklungsaufgaben zeigen.

Die Präsentationsunterlagen und das Beispiel-SQL-Skript sind auf der verlinkten Seite hochgeladen.

Besonders spannend fand ich in der Vorbereitung die Arbeit mit dem OGR-FDW und den automatischen „Import“ (eigentlich Verlinkung) ganzer Open-Data-Sites, sowie die API-Erstellung mit PostgREST.

Linux Week talk: PostgreSQL is my development environment

My topic at Linuxwochen Wien 2019 has the title PostgreSQL is my development environment. The talk will begin at noon on May 2.

It is about using PostgreSQL with foreign data wrappers and extensions to solve „development“ problems without programming.

I also submitted the talk (in English) to the European PostgreSQL Conference in October, maybe I get the opportunity to give it there.

In my opinion, the most interesting parts are the OGR FDW with automatic import of Open Data sites, and creating an API declaratively with PostgREST.

JSON-Verarbeitung mit Jq

(English version)

jq ist ein Werkzeug zur Verarbeitung von JSON-Dokumenten. Es bietet Filter, Umformungen, Umstrukturierungen und andere Möglichkeiten, um die Dokumente in die gewünschte Form zu bringen.

Die JSON-Dokumente, mit denen man als Data Scientist zu tun hat, werden immer komplexer. Z. B. kommt von einer Web-API ein Dokument, das hierarchische, optionale Elemente enthält.

Für Data Mining braucht man jedoch immer eine tabellarische Struktur, ohne hierarchische Elemente und idealerweise auch ohne fehlende Daten. jq hilft dabei, die relevanten Teile der Eingangsdokumente in so eine Form zu bringen.

Nehmen wir folgendes simples Beispieldokument:

{
    "count": 3,
    "category": "example",
    "elements": [
        {
            "id": 1,
            "description": "first element",
            "tags": ["tag1"]
        },
        {
            "id": 2,
            "description": "second element",
            "optional": "optional element",
            "tags": []
        },
        {
            "id": 3,
            "description": "third element",
            "tags": ["tag1", "tag2"]
        }
    ]
}

Wir sehen hier die üblichen Fallstricke komplexer JSON-Dokumente:

  • Elemente auf unterschiedlichen Hierarchiestufen: category, elements/id usw.
  • Optionale Elemente: elements[2]/optional
  • Variable Anzahl von Elementen: elements/tags

jq bietet eine relativ einfache Syntax, um solche Konstrukte zu verarbeiten. Am einfachsten ist es, die Ausdrücke online bei jqplay.org zu entwickeln.

Vielleicht ist das Ziel, eine Tabelle mit category, der Element-Id und den Tags zu erstellen. Der jq-Ausdruck dafür lautet:

{count, category, elements: .elements[] } | {category, id: .elements.id, tag: .elements.tags[]}

Auf den ersten Blick etwas furchteinflößend, aber letztendlich aus einfachen Elementen aufgebaut. Wenn man den Ausdruck Schritt für Schritt bei jqplay ausführt, wird es klarer.

Im ersten Schritt (die Schritte sind mit dem Pipe-Symbol | getrennt) deklarieren wir, welche Elemente wir verarbeiten möchten. Dabei wird eine Liste von Objekten mit {} aufgebaut, darin count und category aus der Hauptebene des Dokuments, und die Elemente als Array. count und category werden dabei wiederholt, damit die „Tabelle“ vollständig ist.

Im zweiten Schritt selektieren wir die category (ursprünglich auf der Hauptebene) und die id jedes Objekts; dazu die Tags als Array. Mit name: .hauptelement.kindelement können wir Elemente selektieren und benennen. Das Ergebnis dieses Schrittes ist eine Liste von Objekten mit category, id, und tag in einer tabellarischen Struktur, die wir etwa in eine Datenbank schreiben oder in einem Data-Mining-Tool verarbeiten könnten.

jq in RapidMiner

Um so komplexe Dokumente in RapidMiner verarbeiten zu können, wäre es praktisch, jq direkt einzubinden. Genau das habe ich gemacht, mit Hilfe von jackson-jq, einer Java-Implementierung.

Zur Vorbereitung müssen wir die Jar-Datei von jackson-jq und zwei Abhängigkeiten ins lib-Verzeichnis von RapidMiner Studio kopieren. Danach steht die Funktionalität im eingebauten Groovy Scripting Operator (Execute Script) zur Verfügung.

Um die Anwendung zu vereinfachen, habe ich zwei RapidMiner-Prozesse erstellt, die in eigenen Prozessen eingebunden werden können. Eine Variante arbeitet an Tabellen (Example Sets), hier muß man beim Aufruf festlegen, welches Attribut die Eingangsdaten enthält und wie das Zielattribut mit dem Ergebnis der Transformation heißen soll. Die andere Variante arbeitet an Document-Objekten, wie sie etwa von Get Page geliefert werden.

In beiden Fällen kann man noch den jq-Ausdruck angeben, festlegen, ob der Output eingerückt formatiert werden soll, und letztendlich wählen, ob das Ergebnis in CSV konvertiert werden soll. Das CSV-formatierte Ergebnis kann RapidMiner mit Read CSV sehr einfach in eine Tabelle umwandeln — das ist bei mir häufig das Ziel.

In jqplay würden wir für den CSV-Output noch folgendes anhängen, und „Raw Output“ auswählen:

 | [ .category, .id, .tag ] | @csv

Damit erzeugen wir ein Array (mit der []-Syntax) und nennen die auszugebenden Elemente. Das Ergebnis wird dann mit @csv umformatiert. (Diesen letzten Schritt erledigt der RapidMiner-Prozess automatisch, wenn der CSV-Output ausgewählt ist.)

Mit etwas Üben und der Hilfe von jqplay lassen sich somit Prozesse erstellen, die aus einem verschachtelten JSON-Dokument relativ einfach eine gut handhabbare Tabelle erstellen.

Um verschiedene Hierarchien innerhalb des Dokuments zu verarbeiten, könnte man auch verschiedene jq-Ausdrücke anwenden, und daraus unterschiedliche Tabellen erhalten.

Processing JSON with jq

jq is a command line tool for processing JSON documents. It can filter, transform and restructure documents to format them in the way we want.

The JSON documents data scientists have to work with are becoming more and more complex. Web APIs often generate documents with hierarchic structure and optional elements.

Data mining, however, needs a tabular structure, without hierarchic elements, and if possible without missing data. jq helps us with the transformation of relevant parts of input documents into this shape.

Take the following example document:

{
    "count": 3,
    "category": "example",
    "elements": [
        {
            "id": 1,
            "description": "first element",
            "tags": ["tag1"]
        },
        {
            "id": 2,
            "description": "second element",
            "optional": "optional element",
            "tags": []
        },
        {
            "id": 3,
            "description": "third element",
            "tags": ["tag1", "tag2"]
        }
    ]
}

This shows the usual pitfalls of complex JSON documents:

  • Elements on different hierarchy levels: category, elements/id etc.
  • Optional elements: elements[2]/optional
  • Variable number of elements: elements/tags

The easiest way to try jq is online at jqplay.org.

We might want to create a table with the category, the element id and the tags. The jq expression for this is:

{count, category, elements: .elements[] } | {category, id: .elements.id, tag: .elements.tags[]}

Scary for sure in the first moment! But when you look at it, it’s built of simple elements. You can always execute it step by step at jqplay to see the effects of each step.

In the first step (the steps being delimited by the pipe symbol „|“) we declare the elements we want to process. We build an object list with { }, taking count and category from the top level and an array of the elements. count and category are repeated to create a proper table.

In the second step we select category and the object id-s, which were on different levels previously. The tags are selected as an array. Using the syntax name: .element.element we can select elements and name them. The result of this step is a list of objects having category, id and tag in a table, suitable for writing into a relational database or processing in a data mining tool.

jq in RapidMiner

It would be useful to process these kinds of documents with jq in RapidMiner. This is what I did, using jackson-jq, a Java implementation of jq.

To prepare, we need to copy the jackson-jq jar file and two dependencies into the RapidMiner Studio lib directory. Then we’re able to use the functionality in the built-in Groovy scripting operator (Execute Script).

I created two RapidMiner processes to make the application easier. These can be used in other processes. There is one variant working on tables (example sets), here you specify the name of the input attribute containing your documents and the target attribute for the transformation result. The other variant works on Document objects, like those coming from Get Page.

In both cases you specify the jq expression and set up the output options. You can indent the output, and convert the result to CSV. The CSV formatted result can be easily transformed to an example set — this is a frequent use case.

If you want to see CSV output in jqplay, check „Raw Output“ and append the following:

 | [ .category, .id, .tag ] | @csv

This creates an array (with the [] syntax) and lists the elements in the output. The result is converted with the @csv step. (The RapidMiner process does this automatically if the csv output is selected.)

This, together with some practicing in jqplay, enables processes that can transform complex JSON documents to straight tables.

To process different parts and structures in the document, just multiply it and apply different jq expressions on the copies.

Der Wert von Bewegungsdaten

Als vor 1-2 Jahren die ostasiatischen Leihfahrrad-Anbieter mitteleuropäische Städte mit ihren Billigrädern zur Miete überfluteten, war die Preispolitik ein wichtiger Punkt in der Diskussion. Es war mehr oder weniger Konsens, daß es den Anbietern langfristig nicht um die wenigen Cent für die Kundenfahrten geht, sondern um die Bewegungsdaten der Kunden.

Jetzt sind E-Tretroller der letzte Schrei, in Wien stehen schon drei Anbieter. Sie müssen ihre Tretroller jeden Abend einsammeln und in der Früh rausbringen, sie zwischendurch aufladen, die Funktion prüfen und warten. Das ist angesichts der Kosten von Arbeit in Österreich schon ein gewagtes Geschäftsmodell. Die theoretische Bewertung der beiden US-Anbieter liegt laut Medien im Milliarden-Bereich. Hierzu gibt es wieder die Annahme, daß zukünftige Einnahmen nicht nur durch die (ziemlich günstigen) Kundenfahrten, sondern durch Auswertung und Verkauf der Bewegungsdaten generiert werden können.

Exemplarische Karte von SCO2T-Fahrten
Hexagonale Felder, aus denen viele SCO2T-Fahrten ausgingen, Ziele der Fahrten. Anzahl der Fahrten durch die Dicke der Pfeile angedeutet.

Denken wir dieses Geschäftsmodell mal für Europa durch. In der EU gelten strenge Datenschutz-Vorschriften, es ist also zumindest legal nicht möglich, Daten wie „XY ist am 1.12.2018 von A nach B gefahren“ zu verkaufen. Sehr wohl kann man aber Daten aggregieren und Dinge auswerten wie „Aus dem Bereich von Alt-Erlaa in den Bereich der UNO-City fahren am Tag durchschnittlich 7 Menschen, 4 davon am Vormittag, 2 am Nachmittag und 1 am Abend“. Nur, wer fragt solche Informationen nach, und wie viel ist er/sie bereit, dafür zu zahlen? Die Stadt Wien, VerkehrsplanerInnen, vielleicht Firmen, die autonomes Fahren entwickeln, andere Verkehrsdienstleister. Nur wird diese Art von Information schon entweder selbst erhoben (die Wiener Linien können das z. B. sicherlich zählen), oder seit Jahren etwa von Mobilfunkfirmen angeboten.

Bei SCO2T haben wir in mehr als vier Jahren, mit vielen tausend Fahrten pro Monat, mit einer großen Präsenz in Fachkreisen und bei Konferenzen, keine einzige Anfrage in diese Richtung bekommen. Das deutet für mich eher darauf hin, daß dieser Markt für aggregierte Bewegungsdaten (noch) nicht existiert, zumindest nicht in Wien.

Neben dem Verkauf der Daten kann man sie natürlich auch intern analysieren, damit Prozesse optimieren und die Dienstleistung für die Kunden verbessern. Z. B. können wir die Scooter nach einer Servicefahrt dort abstellen, wo die Wahrscheinlichkeit einer neuen Miete am höchsten ist. Für diese Analyse sind die Daten von vergangenen Fahrten ohne Kundenbezug notwendig. (SCO2T bezieht grundsätzlich keine personenbezogenen Daten von Kunden in solche Analysen ein — es ist einfach nicht notwendig.)

Meine Schlußfolgerung: Ich als Data Scientist mit GIS-Erfahrung und direktem Zugang zu entsprechenden Bewegungsdaten sehe keinen großen legalen Markt für den Verkauf dieser Daten.

Natürlich könnten Anbieter auf illegale (oder zumindest im Kleingedruckten versteckte und unmoralische) Ideen kommen. Z. B.: Kunde A ist schon öfter ins Donauzentrum gefahren und ist wieder auf dem Weg dorthin. Voraussichtliche Ankunft: 13:30. Wenn man diese Information an Google weitergeben kann, könnte ich mir vorstellen, daß dafür einige Cent gezahlt werden — schließlich kann der Person dann zur richtigen Zeit ortsbezogene Werbung gezeigt werden. Diese Geschäftsmodelle existieren in den USA, und werden als Zukunft der Werbung angesehen — ich sehe aber nicht, wie sie mit der DSGVO vereinbar wären, außer mit expliziter Zustimmung der Kunden. Und selbst wenn — Milliarden wird man damit auch nicht verdienen (nur Google).

Konferenz-Herbst 2017

(English version)

Der Herbst dieses Jahres hält viele spannende Konferenzen bereit.

Gerade ist die Industrial Data Science 2017 in Dortmund zu Ende gegangen. Einen Tag lang hielten verschiedene Vertreter der Industrie hauptsächlich aus Deutschland interessante Vorträge über ihre Data-Science-Projekte. Es ging um komplexe Sachen wie die Vorhersage der Qualität von Stahl schon während des Verarbeitungsprozesses, von Engpässen in flexiblen Produktionsprozessen und um Produkt-Design mit automatischer Erstellung von Prozess- und Teilelisten. Die klassische Industrieanwendung „predictive maintenance“ haben diese führenden Unternehmen also bereits hinter sich. Allerdings wurden viele Projekte als noch nicht in Produktion befindlich angegeben – insofern liegt Österreich vielleicht noch gar nicht so weit zurück.

Das nächste Ereignis ist die Predictive-Analytics-Konferenz am 10. und 11. Oktober in Wien. Diese findet heuer schon zum 13. Mal statt, und ist jedes Jahr ein Pflichttermin für mich. Die Bandbreite der Vorträge in den letzten Jahren war sehr groß, und ich fand immer interessante Anregungen für meine Arbeit.

Weiter geht es dann zwischen 24. und 27. Oktober mit der Europäischen PostgreSQL-Konferenz, diesmal in Warschau. Hier werde ich über die erfolgreiche Migration der Mainframe-DB2-Datenbank nach PostgreSQL in München sprechen, und die Erfahrungen daraus.

Vom 10. bis 12. November findet dann das Pentaho-Community-Treffen in Mainz statt. Hier habe ich auch einen Vortrag eingereicht: Pentaho im Startup. Gemeint ist natürlich SCO2T. Auch wenn wir SCO2T mittlerweile nicht mehr als Startup, sondern als etabliertes Unternehmen und Marktführer bezeichnen, sind die Erfahrungen, die ich unter anderem mit Pentaho gemacht habe, hoffentlich fürs Publikum interessant. Da es schon zu viele technische Präsentationen gab, wurde ich gebeten, im Business-Track zu präsentieren, es werden also eher die Anwendungsfälle als die technischen Details zur Sprache kommen.

2017 Fall Conferences

In this autumn, many interesting conferences present themselves to the data scientist.

The Industrial Data Science 2017 conference in Dortmund, Germany is already over. For an entire day, people from leading (mostly German) industry companies gave interesting talks about their data science projects. The topics were complex: predicting steel quality during the milling process, bottlenecks in flexible production processes and product design with automatic creation of process and parts lists. These companies are already well behind the basic industrial use case of predictive maintenance. However, many of the projects are still not in production – so companies in other countries didn‘t yet lost the race.

The next conference is Predictive Analytics in Vienna, with mostly German talks. This is the 13th iteration of the conference, and I always consider it a mandatory event for me. In the last years, the range of the topics was enormous, and I was always finding new approaches and ideas for my own work.

Still in October, the European PostgreSQL Conference will take place in Warsaw this time. There I‘ll present the successfull migration of a mainframe DB2 database to Postgres in Munich and the experiences I gained from this project.

In November, this year‘s Pentaho Community Meeting is in Mainz. I also submitted a talk there about Pentaho in a startup, with the startup being SCO2T, of course. We don‘t call SCO2T a startup anymore, but an established service provider and market leader. Still, the audience is hopefully interested in learning about the use cases with Pentaho in this environment. There were already too many technical presentations submitted, so I‘ll present in the business track. This means that the talk will be more about use cases than technical details.

PostgreSQL-JDBC-Optionen für RapidMiner und andere Software

(English version)

In verschiedenen Projekten habe ich mich genauer mit den Optionen des PostgreSQL-JDBC-Treibers beschäftigen müssen und damit konkrete Probleme von Java-Anwendungen, unter anderem RapidMiner gelöst. Ich möchte meine Erfahrungen hier teilen und einige der JDBC-Parameter genauer beschreiben.

defaultRowFetchSize (default: 0)

Dieser Parameter steuert die Anzahl der auf einmal angeforderten Zeilen in einem ResultSet. Der Vorgabewert von 0 ergibt eine gute Performance, solange das Abfrageergebnis nicht zu groß wird. Wenn aber sehr viele Daten zurückgegeben werden, die das Programm dann nicht mal braucht, kann der Speicher des Java-Programms (oder RapidMiner Studio) vollständig verbraucht werden.

Meine Empfehlung: zur Sicherheit eine hohe, aber noch sinnvoll in den Speicher passende Zeilenanzahl wählen, z. B. 10.000 oder 100.000. Dadurch wird nicht alles gleich aus der Datenbank geladen, sondern erst wenn die Anwendung die nachfolgende Zeile anfordert.

RapidMiner lädt die Abfrageergebnisse komplett in den Speicher, diese Einstellung bewirkt also nicht so viel wie bei einem Programm, das die Daten sequenziell liest und verarbeitet. Sie kann aber beim Einschränken des Speicherverbrauchs eines Prozesses helfen, und auch bei Verwendung von Stream Database.

stringtype (default: VARCHAR)

Prepared Statements sind bei der Entwicklung von Datenbankanwendungen sehr empfehlenswert. Auch RapidMiner verwendet sie z. B. in Write Database, Update Database und optional in Read Database.

Diese Statements haben folgende Form:


SELECT a, b, c FROM tabelle WHERE c1 = ? and c2 = ?;

INSERT INTO tabelle (a, b, c) VALUES (?, ?, ?);

Für jedes Fragezeichen wird ein Wert mit Datentyp eingegeben. Das vermeidet Typkonversionsfehler und SQL Injections, die sonst viel zu leicht auftreten (das ‚O’Connor‘-Problem).

stringtype = VARCHAR (die Standardeinstellung) bewirkt, daß PostgreSQL als String übergebene Parameter explizit als VARCHAR betrachtet. Das verursacht in einigen Situationen Probleme:


SELECT ... WHERE datumsfeld = ?; -- Datum als String übergeben

INSERT INTO booltabelle (boolfeld) VALUES (?); -- 'true' oder 'false' als String übergeben

Meine Empfehlung: stringtype = unspecified. Das erlaubt z. B. in RapidMiner die Verwendung von korrekt formatierten Datumsangaben in Nominal-Feldern, oder auch von Booleans (true/false) mit Write Database. Es hilft auch bei Legacy-Anwendungen, die mit einer anderen Datenbank entwickelt wurden, und z. B. Zeitstempel als Text an die Datenbank übergeben.

Es wären Situationen denkbar, in denen die Einstellung „unspecified“ Probleme verursachen kann, z. B. wenn die Eingabe nicht auf korrekt formatierte Daten eingeschränkt ist. Dann würde nicht schon das erste Einfügen fehlschlagen, sondern erst der Datensatz mit den falschen Daten. Die Ergebnisse in der Datenbank wären also unvollständig.

ApplicationName

Dieser Parameter kann mit einem beliebigen String belegt werden. Für Datenbank-Admins hilft es manchmal zu wissen, welche Anwendung und welcher User z. B. eine aufwändige Abfrage ausführt.

Meine Empfehlung: Den Namen der eigenen Anwendung eintragen.

currentSchema

Mit diesem Parameter kann der Suchpfad (search_path) festgelegt werden. PostgreSQL sucht standardmäßig in den Schemata pg_catalog, $user und public. Wenn die eigenen Tabellen z. B. im Schema „datamining“ liegen, können sie mit currentSchema=datamining direkt angesprochen werden.

Diese Einstellung kann in speziellen Situationen helfen, wenn z. B. eine migrierte Anwendung ein eigenes Schema verwendet und nicht darauf vorbereitet ist, Schema-Namen anzugeben.

Meine Empfehlung: Nur in begründeten Sonderfällen ändern. Die Änderung von search_path bewirkt, daß die JDBC-Verbindung sich anders verhält als z. B. ein SQL-Client (solange man diesen nicht auch umstellt). Das kann zu subtilen, erst später bemerkten Fehlern führen.

Angabe der JDBC-Parameter

Im Allgemeinen werden die Parameter an die URL der JDBC-Verbindung angehängt, z. B. so:

jdbc:postgresql://server/database?stringtype=unspecified&defaultRowFetchSize=10000&ApplicationName=user@RapidMiner

RapidMiner bietet in Manage Database Connections unter Advanced eine Liste der einstellbaren Parameter, die aber defaultRowFetchSize nicht anbietet. Solche Parameter kann man einfach an den Inhalt des Feldes „Database scheme“ anhängen und die URL überprüfen.

PostgreSQL JDBC parameters for RapidMiner and other software

Some of my projects required working with parameters of the PostgreSQL JDBC driver and using them to solve problems in Java applications like RapidMiner. I’d like to share what I learned and describe some of the parameters in detail.

defaultRowFetchSize (default: 0)

This parameter sets the number of rows that are fetched together in a ResultSet. The default value of 0 results in a good performance as long as the query result doesn’t become too large. But if the query returns a huge amount of data, the memory usage of the Java application (e. g. RapidMiner Studio) grows by a large amount.

I recommend setting a large number that limits the memory requirements, for example 10,000 or 100,000 according to the capabilities of the server and the application. This limits the number of rows fetched from the database initially. The subsequent rows will be fetched when requested by the application.

RapidMiner loads query results into the memory anyway, so this setting doesn’t change its behaviour much. Still, it can help limiting the memory usage of a process, and when using Stream Database.

stringtype (default: VARCHAR)

The recommended way to write SQL statements in application development is to use prepared statements. RapidMiner uses these in Write Database, Update Database and optionally in Read Database.

Prepared statements look like this:


SELECT a, b, c FROM tablename WHERE c1 = ? and c2 = ?;

INSERT INTO tablename (a, b, c) VALUES (?, ?, ?);

Each question mark gets a typed value assigned. This avoids type conversion errors and SQL injections that are all too easy to make otherwise (the ‚O’Connor‘ problem).

The default setting stringtype=VARCHAR forces PostgreSQL to always interpret string parameters with the VARCHAR type. This causes problems in some situations:


SELECT ... WHERE datecolumn = ?; -- date specified as string

INSERT INTO booltable (boolcolumn) VALUES (?); -- 'true' or 'false' strings

I recommend setting stringtype=unspecified. This adds flexibility e. g. in RapidMiner, for example nominal fields with dates or booleans (true/false) with the Write Database operator. It also helps with legacy applications developed with a different database in mind, that use strings to represent timestamps in the database.

There might be situations where „unspecified“ is not the right setting. If the input is not always correct, the process would only fail when encountering the wrong data, so it might end up with an incomplete data set in the database.

ApplicationName

This parameter takes an arbitrary string. It is helpful for database admins so they can see the application and the user behind long-running queries.

I recommend setting the name of the application in this parameter.

currentSchema

This parameter changes the search_path of the database. PostgreSQL searches for non-schema qualified objects in the following schemas: pg_catalog, $user, public. If your tables are in the schema „datamining“, you can set currentSchema=datamining so you can refer to them directly.

This setting can be useful in migration settings, e. g. when the legacy application uses tables in a schema but isn’t prepared to specify the schema name in queries.

I recommend leaving this setting empty and only changing it when required. When you change search_path, your JDBC connection in the application will work differently from e. g. the JDBC client (if that is left with the default settings). This might cause subtle problems later.

Setting JDBC parameters

Usually you can simply append the parameters to the JDBC connection URL like this:

jdbc:postgresql://server/database?stringtype=unspecified&defaultRowFetchSize=10000&ApplicationName=user@RapidMiner

RapidMiner offers a list of parameters in Manage Database Connections with the Advanced button. This list doesn’t offer defaultRowFetchSize, however. You can still specify this parameter by appending it to the „Database scheme“ input field and checking the URL below.

Linuxwochen-Vortrag: Open Source im Startup

Ich halte auch heuer einen Vortrag bei den Linuxwochen Wien, diesmal mit dem Titel „Open Source im Startup”. Es ist eine große Ehre, gleich den ersten Vortrag nach der Eröffnung halten zu dürfen.

Diesmal geht es weniger um mein Kernthema Data Science, sondern um allgemeine IT und den Einsatz verschiedener Open-Source-Lösungen in einem Startup. Ich bin ja „nebenbei“ der CIO (und gleichzeitig die IT-Abteilung) von SCO2T, dem Roller-Sharing in Wien.

Im Vortrag geht es um Technologien, die ich teilweise auch schon hier im Blog vorgestellt habe: PostgreSQL und PostGIS, Foreign Data Wrappers, den Pentaho-Stack, aber auch um neue Themen wie Web-APIs mit PostgREST, Traccar und so weiter.  Ich zeige einige Beispiele, wie man als Nicht-Programmierer mit eher dem Bereich Data Science zugehörigen Werkzeugen auch komplexe-IT-Systeme aufbauen kann.

Der Vortrag beginnt am Donnerstag, 4. 5. 2017 um 10 Uhr im Raum F0.01 am FH Technikum Wien, Höchstädtplatz 6.

Auf der Vortrags-Seite im Programm werden auch meine Folien hinterlegt werden, außerdem gibt es dort wie jedes Jahr die Möglichkeit, eine Bewertung des Vortrags abzugeben.

Es gibt wie jedes Jahr spannende Vorträge an allen drei Tagen, ich werde wohl öfters in einem der Hörsäle anzutreffen sein.

Window Functions in RapidMiner

(English version)

Window-Funktionen in RapidMiner

Richtige Datenbankserver wie PostgreSQL haben seit geraumer Zeit den SQL-99-Standard umgesetzt, der unter anderem Window Functions beschreibt.

Mit Window Functions lassen sich gruppenbezogene Statistiken und Kennzahlen berechnen, ohne die Ergebnismenge zu gruppieren. (Dies ist der Unterschied zur klassischen Aggregierung mit GROUP BY.) Es gibt eine Menge Anwendungsbeispiele: es lassen sich laufende Summen, gleitende Mittelwerte, Anteile innerhalb der Gruppe, gruppenweise Minima oder Maxima und noch viele andere Dinge berechnen. Manche Leute meinen, daß mit Window Functions eine neue Ära für SQL begonnen hat, und ich neige dazu, ihnen zuzustimmen.

RapidMiner hat bislang keine Window Functions eingebaut. Erfahrene Data Scientists, die Bedarf an dieser Funktionalität hatten, haben diese mit verschiedenen Operatoren (Loops, gruppenweise Aggregation und Join usw.) selbst nachbauen können, aber das ist alles andere als trivial.

Um die Funktionalität für einen größeren Benutzerkreis zu öffnen und gleichzeitig eine wiederverwendbare Implementierung zu schaffen, habe ich das Projekt rapidminer-windowfunctions ins Leben gerufen und eine erste funktionierende Implementierung hochgeladen.

Alle im RapidMiner-Operator „Aggregate“ eingebauten Aggregationsfunktionen lassen sich verwenden: sum, average, minimum, maximum usw. Zusätzlich sind die Funktionen row_number, rank und dense_rank verfügbar.

Im Projektordner sind der eigentliche Prozess und aktuell drei Beispielprozesse enthalten, um gleich verschiedene Anwendungsmöglichkeiten testen zu können.

Golf-Datensatz: Gruppenmittelwert der Temperatur und Rang innerhalb der Gruppe für Luftfeuchtigkeit

  • Golf: Der berühmte Golf-Dataset wird aus dem mitgelieferten Beispiel-Repository geladen. Für jede Gruppe basierend auf dem „Outlook“-Attribut wird die Durchschnittstemperatur berechnet und als Attribut hinzugefügt. Ein zweites neues Attribut enthält den Rang des Datensatzes bei Sortierung nach dem Wert der Luftfeuchtigkeit. Gleiche Werte erhalten den gleichen Rang.
  • Iris: Ein weiterer Standard-Dataset, Iris, wird geladen, und es wird pro Spezies der Durchschnittswert fürs Attribut „a3“ berechnet. Dieser Mittelwert wird dann genutzt, um Exemplare herauszufiltern, die mehr als 10 % vom Gruppenmittelwert entfernt sind.
  • Deals: Der mitgelieferte Dataset „Deals“ wird geladen. In jeder Kundengruppe aus Geschlecht und Zahlungsmethode werden die drei ältesten Kunden gesucht, die anderen werden herausgefiltert.

Das zeigt schon die Bandbreite der Möglichkeiten, die Window Functions bieten. Die Möglichkeit, sie leicht einzusetzen und Indikatoren sowie Kennzahlen wie „Transaktionszähler des Kunden im Monat“, „Anteil des Produkts an der Monatssumme“ und ähnliche erzeugen zu können, wird viele Prozesse vereinfachen, oder neue Möglichkeiten eröffnen.

Implementierung

Nach einigen Prüfungen, z. B. ob die benötigten Makros gesetzt sind, werden neue Attribute zur Gruppierung und Identifizierung von Examples angelegt. Das zusammengesetzte Gruppierungsattribut wird dabei aus den Werten der als groupFields angegebenen Attribute generiert. Das Identifizerungs-Attribut muß mit einem Groovy-Skript generiert werden, da Generate Id mit vielen Datensätzen nicht funktionieren würde. (Generate Id funktioniert nicht, wenn der Datensatz bereits ein Attribut mit der Rolle id enthält.)

Die drei Spezialfunktionen, die in Aggregate nicht enthalten sind, werden gesondert behandelt. Die Untergruppen werden nach dem ausgewählten Attribut sortiert und der Datensatzzähler bzw. die Rangfolge berechnet.

Die Standard-Aggregierungsfunktionen von RapidMiner werden einfach auf jede Subgruppe angewendet, dabei entsteht jeweils eine gruppierte Zeile. Diese wird wieder mit den Originaldaten gejoint.

Einschränkungen

Gegenüber dem SQL-Standard und der in Datenbanken implementierten Funktionalität fehlt noch einiges. Z. B. erlauben Datenbanken bei Funktionen wie SUM die Angabe eines Sortierkriteriums und berechnen dann eine kumulierte Summe für jede Zeile, statt die gleiche Summe wiederholt auszugeben.

Der Prozess ist auch recht langsam, wenn viele Gruppen existieren. Dies ergibt eine große Anzahl von Filterungen in der Schleife. Bei den speziellen Rang- und Zählerfunktionen ist das Problem besonders ausgeprägt, da in jedem Durchlauf ein Groovy-Interpreter gestartet wird, was erhebliche Zeit kostet.

Das Konzept von Window-Definitionen geht in SQL-Datenbanken über Selektion von Gruppen hinaus. Z. B. kann man in SQL auf den vorherigen oder nächsten Datensatz zugreifen (LAG bzw. LEAD), ein fixes Fenster von X Zeilen definieren, und in den Daten „nach vorne“ schauen. Diese Dinge sind gegenwärtig nicht im Prozess eingebaut.

Mögliche Erweiterungen

Es spricht nichts dagegen, einige von den in SQL zur Verfügung stehenden Funktionen wie percent_rank, ntile oder first/last_value einzubauen. Dies wird bei Bedarf sicher passieren.

Die Funktionalität, über ORDER BY das Verhalten der Aggregierungsfunktionen zu ändern (z. B. für kumulierte Summen), erscheint mit RapidMiner-Mitteln nicht einfach. Allerdings ließe sich die kumulierte Summe leicht mit einem weiteren Groovy-Skript implementieren.

Bezugsquelle

Das Projekt kann auf Github heruntergeladen oder ausgecheckt werden. Es enthält Dokumentation und Beispielprozesse. Die Lizenz ist Apache 2.0, somit sind Einsatz und Weiterentwicklung uneingeschränkt möglich. Es ist also ein klassisches Open-Source-Projekt, das von der Beteiligung und Weiterentwicklung durch die Community leben soll.

Window functions in RapidMiner

For powerful database software like PostgreSQL the SQL-99 standard has been implemented for a long time. Window functions are an important part of SQL-99.

Window functions are used for calculating groupwise statistics and measures without actually grouping the result. (This is the difference between Window functions and the well-known aggregation with GROUP BY.) There are many applications: running sums, moving averages, ratios inside a group, groupwise minimum and maximum and so on. Some people consider the introduction of Window functions the beginning of a new era for SQL. I agree with this quite strongly.

RapidMiner doesn’t offer Window functions, yet. Experienced data scientists were able to build this functionality when they had to, using loops, aggregation and join, but these processes are not easy to create and debug.

My goal is to open this functionality for a larger group of potential users and to create a reusable implementation. So I started the rapidminer-windowfunctions project and uploaded the first working version.

All functions built into RapidMiner’s Aggregate operator can be used: sum, average, minimum, maximum etc. Additional functions are row_number, rank and dense_rank.

The project ships with the actual process and a number of example processes. These demonstrate different applications of Window functions on public datasets available in RapidMiner Studio.

Golf dataset with groupwise temperature average and rank by humidity

  • Golf: The process loads the well-known Golf dataset from the Samples repository. For each group defined by the attribute “Outlook”, the average temperature gets calculated. A second attribute ranks the examples by the attribute “Humidity”. Identical values get the same rank.

  • Iris: This is another standard dataset, available from RapidMiner’s Samples repository. The process calculates the average value for the attribute “a3”. This group average is used to filter out examples which differ from the average by more than 10 %.

  • Deals: Another data set built into RapidMiner. This process considers all combinations of Gender and Payment Method as groups and ranks the customers based on their age. Only the 3 oldest customers per group are retained.

This is just a small sample of all the functionality available with Window Functions. Being able to use them easily for building indicators and measures like “transaction counter per customer and month” or “the product’s contribution percentage” will open new possibilities for modelling or reporting.

Implementation

The process checks a few preconditions, for example required parameter macros. It creates new attributes for grouping and identifying examples. The grouping attribute is built from all values given in the groupFields parameter. The identifying attribute needs to be generated in a Groovy script, as Generate Id would fail on too many real-world datasets. (It doesn’t work when the dataset already has an attribute with the role id.)

The three special functions not available in Aggregate are implemented with Groovy scripts. The process sorts the subgroups by the selected attributes and calculates the record counter or the rank.

The implementation of the standard aggregations is simpler: each subgroup is aggregated and the result is joined with the original data.

Limitations

Some functionality is missing compared to the SQL standard and to database systems. For example, in SQL databases, you can use ORDER BY in the window function to specify an ordering and calculate cumulative sums for each row instead of a groupwise sum.

The process is quite slow if many groups exist in the dataset. Having many groups results in a large number of filters in the loop. The performance is especially bad with the special ranking and counter functions because they start a Groovy interpreter in each iteration, which takes a lot of time compared to other operators.

The concept of window definition in SQL databases covers more than just the selection of groups. For example, you can access the previous and next records (LAG and LEAD), define a fixed window of N rows, and look forward in the data. These things are not available in the current version of the process.

Possible extensions

It’s entirely possible to implement more SQL standard functions like percent_rank, ntile and first/last_value. This will happen for sure when there’s a need.

It seems to be hard to change the behaviour of aggregation functions using ORDER BY (e. g. for cumulative sums) with RapidMiner means. However, special cases like the cumulative sum could be implemented with another Groovy script.

Getting the process

You can download the process or check it out on Github. The project also contains documentation and example processes. The license is Apache 2.0, so there are no restrictions on usage or further development. It is intended to become an Open Source project with the participation of and further development by the community.