Cassandra CQL mit JDBC-Driver

Hatte endlich mal Gelegenheit mich mit einer NoSQL Datenbank zu beschäftigen: Cassandra von Apache. Allerdings fühlte ich mich aus Anwender – in meinem Fall also Anwendungsprogrammierer – in die Steinzeit der Datenbankprogrammierung zurückversetzt: es gibt nur proprietäre Schnittstellen und die sind auch nicht abgekündigt (Thrift). Selbst Apache empfiehlt auf ein abstrakteres API wie zum Bespiel Hector zu setzen.

Leider fühlt sich auch Hector in keiner Weise so an wie man es von konventioneller Datenbank-Programmierung gewohnt ist. Das Java-API ist nach meinem Geschmack “gewöhnungsbedürftig” um es einmal diplomatisch auszudrücken.

Dabei gibt mit Spring-JDBC (oder neuerdings mit Spring-Data) längst gute Beispiele wie man es gut machen kann. Jetzt kann man natürlich einwenden, dass diese “alten” Ansätze für SQL-Datenbanken gemacht sind und sich daher nicht für NoSQL Lösungen eignen, aber wenn man zweimal hinsieht, dann merkt man schnell, dass das gar nicht stimmt.

Der Unterschied bei der Sicht auf die Daten besteht meiner Meinung nach im Wesentlichen im Datenmodell, oder in der Art wie man zum Datenmodell kommt: entweder klassisch relational und normalisiert, oder Abfrage-Orientiert und de-normalisiert.

Wenn das Datenmodell aber steht, ließe sich mit den Daten eigentlich genauso arbeiten wie mit SQL-Datenbanken: über eine Abfrage-Sprache. Im Falle von Cassandra ist das CQL. Parallelen gibt es mit Keyspace = Database, ColumnFamily = Tabelle, und Column / Row genug. Die Einschränkungen / Erweiterungen con CQL sind eben der Datenbank geschuldet (z.B. kein Join) und stören erst mal nicht, wenn man sich für das NoSQL Modell entschieden hat.

Jetzt gibt es mit Cassandra-JDBC sogar einen JDBC-Treiber für Cassandra, der auch CQL über JDBC in jeder Java-Anwendung verfügbar macht. Man sollte also meinen alles Handwerkzeug in Händen zu halten, um “vernünftig” arbeiten zu können.

Leider ist dem im aktuellen Release 1.0.5 (Dez 2011) von Cassandra nicht so.

Die Umsetzung ist etwas lückenhaft, so dass praktisch bei jeder anderen Anwendung (außer “Hello World”) Probleme auftreten.

Spalten sind nicht löschbar

Will man eine Spalte löschen, dann wird man im normalen SQL ein UPDATE … Feldname = NULL verwenden, was aber beide Spaltenorientierten Cassandra mit CQL nicht funktioniert. Dort muss stattdessen die Spalte selbst gelöscht werden mit DELETE Column(s) FROM ColumnFamily WHERE …

Unnötig umständlich wie ich finde. Man ist gezwungen UPDATES auf Rows in ein UPDATE und ein DELETE Statement aufzuspalten, wenn man einen Teil der Spalten löschen will. Gerade weil Cassandra aber kein festes Schema mit beliebig vielen Spalten, die auch nicht notwendigerweise gefüllt sein müssen, unterstützt, ist dies doppelt ärgerlich.

Selects auf NULL-Spalten funktionieren nicht

Wie schon erwähnt wird man in einer Cassandra Persistenz sicher häufig auf Rows treffen, bei der nicht alle Spalten mit Werten belegt sind. Statt bei einer CQL Anfrage dann aber NULL, oder zumindest in der JDBC Darstellung NULL bzw. den passenden Default zu liefern, stolpert man über eine Exception. Man kann gar keine Spalten abfragen, die nicht gesetzt sind.

Unzureichende Expression-Language

Cassandra kennt zwar bestimmte Typen Spalten. Allerdings liefert CQL kaum ausreichen Ausdrucksmöglichkeiten mit diesen Typen umzugehen. Man kann nicht einmal einen Timestamp erzeugen, ausser den nackten Long-Wert direkt einzugeben, um nur ein Beispiel zu geben. Dies erschwert die Formulierung von Abfragen wiederum unnötig. Man hätte leicht bestehende Implementierungen von ELs adaptieren können, um halbwegs verwendbare Ausdrücke in CQL einsetzen zu können.

PreparedStatements funktionieren nicht

In JDBC ist es eigentlich der Normalfall PreparedStatements zu nutzen. Nicht nur weil man dem Server Gelegenheit gibt, die Anfragen zu optimieren, auch Injection wird damit wirkungsvoll verhindert. Leider unterstützt Cassandra 1.0.5 solche Anfragen bislang nicht. Der JDBC-Treiber bietet sie dennoch an.

Wie man in der Beschreibung und im Quellcode nachlesen kann, werden die Bindings jedoch schon auf der Clientseite aufgelöst und dann zum Server geschickt. Damit könnte man leben, wenn das wenigstens funktionieren würde. Leider ist auch hier die Implementierung fehlerhaft, sodass oft genug die Bindung schlicht falsch ist und der Server die Anfrage mit einem Fehler quittiert.

Fazit

Will man Cassandra einsetzen, hat man sich so an das eine oder andere zu gewöhnen (oder wieder zu gewöhnen). Und damit meine ich nicht in erster Linie die Art der Datenmodellierung. Ich jedenfalls fühlte mich in mancher Hinsicht um eine paar Jahre in die Vergangenheit zurück versetzt, als man mit Oracle noch per Oracle Call Interface (OCI) sprechen musste. Aber wenns denn Cassandra sein muss …

Dieser Beitrag wurde unter Java veröffentlicht. Setze ein Lesezeichen auf den Permalink.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *