JBrisbin.com

Riak support in Grails GORM

22
Nov

Riak support in Grails GORM

Thanks to all the great help from the SpringSource and Basho folks over the last several weeks. I'm happy to start talking more in-depth about what I've been tweeting about my Grails GORM support for Riak.

The Problem

I started skipping down this garden path because I wanted to be able to easily bridge the Groovy world in which we develop our new internal, browser-based applications, and the more old-timey data sitting on our AS/400. I tried using the Java client for Riak to do some basic and low-level work and it just wasn't exactly what I was looking for. I'm a bit of a perfectionist, so I'm notoriously difficult to please. :)

I decided that working on an integration layer between Riak and Java using the great tools introduced in Spring 3.0 (and particularly in Spring 3.0.5 with the conversion abstractions) like the RestTemplate and the HttpMessageConverter would be the best approach. Not finding anything even being talked about more than pure vaporware, I simply jumped in feet first and started throwing down code as fast as I could.

GORM, meet Spring Data

Spring Data is a new[ish] project at SpringSource that's trying to to make data access easier for those stores that don't use SQL as the query or interaction language. That includes basic NoSQL stores like Redis, document stores like MongoDB, and hybrid stores like Riak. There's more to it than this, of course, but GraphDBs are a little beyond the scope of this discussion and we're only really concerned with Riak at the moment.

One of the long-term goals of Graeme Rocher's inconsequential project and Mark Pollack's spring-data project, is to start drifting the two data access methodologies together. The idea is to have a generic and useful NoSQL abstraction that developers can use that won't lock them into a specific platform (though I'd like to see an example of when this lofty goal has ever really been met! :) and extend that toward the Grails side with additional tools on top of spring-data to make a full-blown ORM (with Query implementations, indexing, and the whole nine yards).

Spring 3.0's RestTemplate is a great and powerful abstraction over HTTP REST calls that makes writing applications that use REST superbly easy. Since Riak has a first-class REST API, it was actually pretty easy to write a from-scratch "client" for Riak that does automatic object conversion (currently assuming JSON format in the backend) and uses the Spring stack all the way from the ground up. This means there are no external dependencies beyond Spring 3.0 (which I assume you're using anyway, right? No? Why in the world not!? :).

There are two parts to the Riak interaction I've written:

  1. The spring-data portion -- This handles the low-level HTTP access, including object serialization and deserialization (simply by setting the "Content-Type" to "application/json", an object will be marshalled and unmarshalled automatically by the internal MappingJacksonHttpMessageConverter).
  2. The Grails GORM portion -- This handles the GORM-specific portion of the data access, which builds on top of spring-data and implements a Query interface which uses Javascript Map/Reduce underneath to query for data that has been persisted, either by GORM, or any other process that can write data into Riak.

Examples

If you've used Grails GORM for your object models, then there's really nothing else you need to do. As I'm writing this, the Riak support passes all but one of the almost 100 compatibility tests. There shouldn't be anything more you need to do. You can set a URL using the following config options:


grails.riak.defaultUri = "http://localhost:8098/riak/{bucket}/{key}"
grails.riak.mapReduceUri = "http://localhost:8098/mapred"

And that's it! :)

If you want to execute your own custom Map/Reduce code, then you can execute it against your models like so:


  MyModel.mapreduce.execute([
    map: [
      source: '''\\
      function(v) {
        ejsLog('/tmp/mapred.log', 'data: ' + JSON.stringify(v));
        var o = Riak.mapValuesJson(v);
        ...
        return [o];
      }
      '''
    ],
    reduce: [
      source: "function(v) { return v.length; }"
    ]
  ])

The code hasn't yet been released. There will be more information as I get the nagging little problems ironed out. But so far things look on track to get something you can start playing with by the week after Thanksgiving.

blog comments powered by Disqus