Wörter zählen

Am Donnerstag war Soundcloud wieder einmal so freundlich, seine Räume für das Treffen des FunClubs zur Verfügung zu stellen. Zu diesem Treffen sollten die Teilnehmer eine Aufgabe lösen: Wörter in einem Text zählen und die 10 häufigsten Wörter anzeigen.

Die Präsentationen waren sehr interessant. Es waren Lösungen in

  • Bash/Awk
  • Erlang
  • Haskell
  • Scala
  • Lua
  • Clojure
  • Common Lisp
  • R
  • C

zu sehen. Sehr interessant war, dass es doch trotz des sehr einfachen Problems sehr viele unterschiedliche Wege zu Lösung gibt.

Auch die Vergleich der Performance waren sehr interessant. In dieser Hinsicht war der Beitrag in C das Highlight des Abends (und zurecht auch am Schluss). Während bei den Hochsprachen Lua bei der Verarbeitung des 500MB Korpus mit ca. 20 Sekunden die Führung einnahm, so wurde diese Zeit durch die Implementation in C um Größen (2,8 Sekunden) geschlagen. Besonders interessant dabei war, wie viele Annahmen über das Problembereich gemacht wurden und welche Vereinfachungen der Implementation sich daraus ergeben – z.B. wenn man von einem belletristischen Text in englischer Sprache ausgeht kann man einen besonders einfachen und schnellen Algorithmus zur Berechnung des Hashwertes nehmen, da vermutlich kaum mehr als 100.000 Wörter vorkommen werden. Dafür war es in Zeilen gerechnet auch das längste Programm.

Hinsichtlich der optischen Reize war die Präsentation mit Keynote die Ansprechendste.

Leider ist wegen der großen Beteiligung und der vielen Beiträge die Diskussion des Problems etwas zu kurz gekommen. Es war aber trotzdem ein anregender Abend.

Posted in Programmierung | Kommentare deaktiviert

Umbenennen von Postgres Typen

In PL/pgSQL, eine der Programmiersprachen für die serverseitige Programmierung in PostgreSQL, werden das Interface der Prozedur und Body unterschiedlich behandelt. Der Body wird beim ersten Aufruf in einer Session kompiliert, für SQL werden Prepared Statements und ggfs. auch Ausführungspläne erstellt und diese im Cache bis zum Ende der Session gespeichert. Innerhalb eines Bedingungsbaums werden so nur die Statements vorbereitet, die auch benötigt werden (siehe Dokumentation).

Typen können in PostgreSQL erstellt und als Parameter oder Variablen referenziert werden. Typen in Parameterdeklarationen werden beim Erstellen der Funktion in die OID aufgelöst, Typen in Variablen Deklarationen zu Beginn der Session, wenn der Body compiliert wird.

Wenn ein Typ mit ALTER TYPE geändert wird, dann bleibt seine OID gleich. Wurde diese OID in einer Funktion als Interface definiert, so wird damit die gespeicherte Interface Definition geändert. Die im Cache befindlichen Funktionen kennen diese Änderungen nicht, weil das vorbereitete Statement durch ein ALTER TYPE nicht invalidiert wird. Sind im Cache nun aber Aufrufe des Interfaces enthalten, so verweisen diese auf den alten Typ. Wird eine neue Session erstellt, so wird der Body neu kompiliert und erst danach wird der neue – geänderte – Typ referenziert.

Wenn man nun durch ALTER TYPE den Namen des Typs ändert, dann funktionieren die aktuell im Cache enthaltenen vorbereiteten Statements weiterhin.Im Quellcode der Funktion sind jedoch noch den alten Namen des Typs enthalten. Hier könnte man auf die Idee verfallen, einen neuen Typen anzulegen, welcher den Namen des alten Typs vor der Änderungen erhält.

Wenn man jedoch daneben einen neuen Typ anlegt, der den gleichen Namen hat wie der geänderte Typ, so werden die neu kompilierten Prozeduren beim Aufruf (zur Ausführungszeit) immer noch fehlschlagen, weil es keine Funktion mit der neuen OID existiert! Die Funktion wird gesucht mit dem passenden Typ im Namen. Der Typname wird aufgelöst nach der OID und die passende Funktion mit gesucht mit der neuen OID gesucht. Eine solche Funktion gibt es aber nicht, da das Interface nicht neu compiliert wurde.

In diesem Fall, wenn Typen im Interface von Funktion geändert werden, müssen diese Funktionen auch neu erstellt werden. Das führt dazu, dass die bestehenden vorbereiteten Statements im Cache invalide werden und die Funktionen bei einem neuen Aufruf erneut kompiliert werden.

create type mutableType as (myval int);
--
create or replace function useMutableType(mut mutableType)
returns int stable language plpgsql as $body$
begin
return mut.myval;
end;
$body$

create or replace function invokeMutableTypeFunction()
returns int language plpgsql as $body$
declare
 val mutableType;
begin
 val.myval := 1;
 return useMutableType(val);
end;
$body$

local_db=# select * from invokeMutableTypeFunction() ;
invokemutabletypefunction
---------------------------
1
(1 row)

In einer anderen Session kann man den Type ändern.

alter type mutableType rename to mutatedType;

In der ersten Session kann das Statement weiterhin ausgeführt werden, führt man das Select jedoch in der zweiten Session aus, führt das zu folgenden Fehler

local_db=# \c local_db
You are now connected to database "local_db".
local_db=# select * from invokeMutableTypeFunction() ;
ERROR:  type "mutabletype" does not exist

 

Posted in Allgemein, Programmierung | Tagged | Kommentare deaktiviert

Objekte im Jasperserver aktualisieren

Sollen die Objekte im Jasperserver Repository aktualisiert werden (von einer Testumgebung auf eine Produktionsumgebung), muß man beachten, daß man die Datenquelle nicht überschreibt. Die Datenquelle wird referenziert und wird mit in den Exportordner oder das Export-Zipfile geschrieben. Löschen der Datenquelle aus dem Exportfolder vor dem Import ist auch keine Lösung, denn ohne Datenquelle können die Objekte jedoch nicht aktualisiert werden. Dann erscheint die Exception:

08:00:44,530 ERROR FileSystemInput:73 - java.io.FileNotFoundException:

(Interessanterweise kann eine Ressource ohne Datasource im Dateisystem importiert (hinzugefügt) werden, wenn die Ressource nicht vorhanden ist – ohne --update Option – und wenn die Datasource im Repository vorhanden ist. )

Das im folgenden beschriebene Verfahren kann auch verwendet werden für das Kopieren der Testumgebung in eine Produktionsumgebung.

Export aus dem Quellsystem

 > cd <installdir/jasperserver-3.5.0>\scripts
 > js-export.bat --output-dir x:\path\jasper --uris /FolderName/AnalysisView

Die Dateien der des Repositories einschließlich der index.xml Datei muß auf das Zielsystem transferiert werden. Diese enthält auch die Datasource des Quellsystems. Im Repository Verzeichnis muß diese Datasource ergänzt bzw. ausgetauscht werden. Im scripts Ordner des Zielsystems dazu die Datasource exportieren:

 > js-export.bat --output-dir c:\Temp\jasperexport --uris /datasources/targetdatasources

Wenn man die entstandene Datei ins entsprechende Verzeichnis des Repository kopiert hat, kann man dieses dann importieren, ggfs auch Objekte aktualisieren:

 > js-import.bat --update --input-dir c:\Temp\jasper

Danach muß man für Änderungen am Mondrian den Jasperserver über die Managementoberfläche des Tomcat neu starten.

Posted in Business Intelligence, Programmierung | Tagged | Kommentare deaktiviert

Funclub about fexprs

Gestern war ich auf einem Meetup des FunclubTim Felgentreff sprach über Fexprs und erläuterte das Konzept und auch die Nachteile. Interessant war, was mit einem solch einfachen Konzept möglich wird. Bei Fexprs werden die Operanden nicht evaluiert, bevor sie an die Funktion übergeben werden. Die Funktion erhält darüber hinaus die Umgebung des Aufrufers und kann darüber entscheiden, ob die Operanden evaluiert werden.

Interessant war die Demonstration, mit wie wenig Kernfunktionen eine Implementation auskommt, die Fexprs evaluiert. Dies ist die Stärke des Konzepts. Leider – und das ist der Nachteil – ist die Ausführung unglaublich langsam. Die statische Analyse kann nicht feststellen, ob ein Operator eine normale Funktion oder eine Fexprs darstellt.

Tim verschärfte das Problem in der Diskussion. Dadurch, dass die Umgebung (die Menge der Symbole und der gebundenen Werte) der Fexpr zugänglich ist, kann diese auch geändert werden kann. Alle späteren Implementationen von Lisp (nach 1980) haben meist auf die Fexprs zugunsten der Macros verzichtet.

Posted in Programmierung | Tagged | Kommentare deaktiviert

Abhängigkeiten in Programmen

Einige wenige Tage Beschäftigung mit Clojure bringt die gewohnten Bahnen ganz schön durcheinander. Einerseits bin ich noch immer wieder erstaunt, wie kurz funktionale Programme werden. Zum anderen stelle ich fest, dass ich beim Review von Code in imperativen Sprachen die Ausdruckskraft funktionaler Sprachen vermisse.

Gegeben sei Prozess, welcher einen langen Liste von Werten aufbaut. Da die Regeln umfangreich sind, wird die Verarbeitung aufgeteilt in verschiedene Methoden/Prozeduren, damit die Prozeduren übersichtlich bleiben.

process1( liste )
process2( liste )

meinRecord ist ein Objekt, was von beiden Prozeduren verändert wird. Es ist aber nicht ersichtlich, ob prozess2 vom Ergebnis von prozess1 abhängig ist. Es kann sein, dass in prozess2 gelesen werden, die in prozess1 gesetzt wurden. Es kann aber auch nicht sein. Dann würde

process2( liste)
process1( liste)

zum gleichen Ergebnis führen. Das macht es einem Entwickler schwer, diesen Ablauf zu ändern oder zu refaktorieren. Der Entwickler, muß manuell die ganzen Abhängigkeiten auflösen, ob process2 von einer Zustandsänderung in process1 abhängt.
Besser wäre es, wenn der Quellcode die Abhängigkeit explizit ausdrückt. Das ist eigentlich das prinzipielle Dilemma von imperativen Sprachen. Besser wäre die Form

B := process1 ( A )
C := process2 ( B )

Hier wird die Liste A nicht (in-place) verändert, sondern ist nicht veränderlich. Damit ist ersichtlich, dass process2 vom Ergebnis von process1 abhängt. Besteht keine Abhängigkeit, dann sollte auch dies erkennbar sein.

A := process1 ( X )
B := process2 ( Y )
C := combine( A, B )

Damit ist auch ersichtlich, dass die Ausführungsreihenfolge von process1 und process2 nicht von Bedeutung ist. Wäre es sicher, dass sie keine Nebenwirkungen haben – wie in rein funktionalen Sprachen – könnten diese Prozesse auch parallel ausgeführt werden. Leider ist nie alles Gute beisammen. Wenn eine Funktion immer das gleiche Ergebnis liefert, wenn man sie mit den gleichen Parametern aufruft, ist das zum Testen ganz schön, aber nicht alle Probleme sind so einfach. Ich bin gespannt, wie man in funktionalen Sprachen zustandsbehaftete Probleme löst.

 

 

Posted in Programmierung | Kommentare deaktiviert

Quellcode Analyse mit JaMoPP

Heute war ich mal wieder auf einer Veranstaltung der JUG-BB. Diesmal ging es um ein Tool zur Quellcode Analyse und Manipulation -JaMoPP.

Basis ist ein auf EMF basierendes Modell des Java-Quellcodes. Der Quellcode kann in das Modell umgewandelt werden und auch wieder geschrieben werden. Das schöne daran ist, dass alle Formatierungen erhalten bleiben – auch Whitespaces sind Elemente des Modells.

Diese Modell ist nun der Programmierung über die API zugänglich. Damit ist nun eine ganz andere Art von Validierung des Quellcodes möglich, als sie beispielsweise Findbugs bietet. Diese Validierungen können insbesondere in größeren Projektteams dazu dienen, die Einhaltung von z.B. Architekturrichtlinien oder Namenskonventionen zu wahren.

Da das Modell auch wieder in die Dateien geschrieben werden kann, ist dieses Tool auch in der Lage, den Quellcode automatisiert zu ändern. Damit können z.B. Klassen durch andere Implementationen ersetzt werden, Objekterzeugungen können durch einen Aufruf einer Factorymethode ersetzt werden etc.

Für JaMoPP gibt es auch ein Eclipse Plugin, das jedoch sehr viel Hauptspeicher erfordert, die Entwickler empfehlen daher den Einsatz über Unittest im CI Server.

Posted in Allgemein | Kommentare deaktiviert

Abenteuer Clojure

Im Laufe der Zeit habe ich schon einige Programmiersprachen kennengelernt. Meiner ersten Schritte habe ich mit Basic auf einem Commode C64 gemacht, dann in dBase die Daten meiner Diplomarbeit ausgewertet und damit das imperative und prozedurale Programmieren gelernt. Dann habe ich das objektorientierte Programmieren mit Powerbuilder, Delphi und Java entdeckt und es im Laufe der Zeit immer wieder neu gelernt. Die wirkliche Idee habe ich vielleicht erst über die Beschäftigung mit Smalltalk verstanden (das Schöne an Smalltalk zeigt z.B. der Artikel Reading Smalltalk).

Das alles war spannend, jedoch war der Schritt vom prozeduralen zum objektorientierten Programmieren nicht besonders groß, da auch die genannten Sprachen imperative Sprachen sind. Er ist nicht vergleichbar mit dem Schritt vom objektorientiert-imperativen zum funktionalen Programmieren mit einer Sprache aus der Lisp Familie. Dank der regen Clojure Community gibt es gute Webseiten, auf denen man diese Sprache erlernen kann. Das Aufregendste daran für mich ist es, ohne Variablen zu programmieren. Das stellt mein gewohntes Denken vor wirklich neue Herausforderungen. Man kann über Algorithmen nicht in der gewohnten Weise denken. Werte sind im Prinzip erst einmal unveränderlich. Das ist ein Abenteuer. Es fühlt sich an, als ob man  das Laufen neu lernte, oder als ob ein Klarinettist auf einmal Geige spielen lernte.

Posted in Programmierung | Kommentare deaktiviert

Verwirrende Meldung

Oracle beantwortet die Abfrage

select (count(*) > 0) from dual

mit der Fehlermeldung

ORA-00907: Rechte Klammer fehlt

Interessanterweise in PL/SQL wird eine äquivalente Anweisung sogar fehlerfrei compiliert, führt aber zu einem Laufzeitfehler mit der gleichen Meldung.
Was auf den ersten Blick verwirrt, ist im nachhinein einfach. Der Ausdruck ist ein Boolean und dieser Datentyp gehört leider nicht zu den SQL Datentypen, sondern nur zu den PL/SQL Datentypen von Oracle.

Eine sprechendere Fehlermeldung hätte Oracle schon spendieren können.

Posted in Allgemein | Tagged | Kommentare deaktiviert

Einschränkungen für DimensionUsage

Wiederverwendung von Dimension ist schön, hat jedoch auch Grenzen. Schema Dimensionen, die über das DimensionUsage Element eingebunden werden, haben bei Mondrian folgende Einschränkung: Diese Dimensionen können nicht für degenerierte Dimensionen (degenerate dimension) verwendet werden. Erklärung findet sich im Pentaho Forum:

We obviously want the shared dimensions to have the same set of members, regardless of which cube they are used in, and your ‘table-less’ shared dimensions wouldn’t behave like that.

Das bedeutet, dass es genau dann zu einem Fehler mit Shared degenerate dimensions kommt, wenn diese Dimensionen in unterschiedlichen Cubes verwendet werden, welche auf unterschiedlichen Fakt Tabellen basiert. In diesem Falle bekommt man folgendenen Fehler:

Mondrian Error:In usage of hierarchy '[hierarchyName]' 
in cube 'NameOfCube', you must specify a foreign key,
because the hierarchy table is different from the fact table.
Posted in Business Intelligence | Tagged | Kommentare deaktiviert

Kanban und Storm

Heute war ein Hadoop Get Together der Scalable Information Retrieval group von Xing. Es gab interessante Vorträge, die sich jedoch nicht primär mit Hadoop auseinander setzten.

Der erste Vortrag von Markus Andrezak handelte über ein Prozessmodell in der Softwareentwicklung. Wie kann man Kanban in der Softwareentwicklung anwenden? Ausgangspunkt seiner Argumentation war das Ziel, dass die Firma möglich schnell Werte realisieren möchte und vom Markt auch schnell ein Feedback benötigt, die bestätigt, dass die Entwicklungen angenommen werden oder nicht. Dazu muss einerseits ein Modell bestehen, dass durch Datenanalyse verifiziert werden kann. Um ein schnelles Feedback zu bekommen, müssen Entwicklungen schneller deployed werden – das heisst tägliche Releases.

Interessant für mich waren verschiedene Aussagen. Das Problem, so meint er, sei das Projektmanagement, welches aus dem Management greifbarer Güter nicht auf Kreativprojekte – bei denen es viel auch um Lernen geht, nicht übertragen lasse. So konnte er durch das Reduzieren der gleichzeitig bearbeiteten Features die Durchlaufzeit erhöhen. Das führte dazu, dass auch die Varianz der Dauer der Implementation von Features deutlich reduziert werden konnte. Die Kosten für Transaktionen (Auslieferungen) sind deutlich geringer, das Risiko ist geringer. Auslieferung von Bugfixes ist kein Sonderfall, kleine Änderungen ausliefern ist der Standardfall.

Der zweite Vortrag von Martin Scholl beschäftigte sich mit dem Framework Storm. Leider ist die Einleitung (mit einer netten musikalischen Analogie) recht lang geworden. Darum hat dem Vortragenden die Zeit für verschiedene technische Details und Beispiele nicht mehr gereicht. Storm ist eine Plattform für Echtzeit Analyse von Daten. Das System verarbeitet permanent einen Strom von Ereignissen und kann auf diese reagieren. Die Knoten können auf verschiedene Rechner verteilt werden. Das System stellt sicher, dass jedes Event mindestens einmal verarbeitet wird. Versprochen wurde außerdem, dass sich das System viel leichter aufsetzen lassen soll als Hadoop. Muß man mal ausprobieren.

Posted in Allgemein | Kommentare deaktiviert